summaryrefslogtreecommitdiff
path: root/src/test/kotlin/dev/dnpm/etl/processor
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/kotlin/dev/dnpm/etl/processor')
-rw-r--r--src/test/kotlin/dev/dnpm/etl/processor/input/MtbFileRestControllerTest.kt277
-rw-r--r--src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt1404
2 files changed, 852 insertions, 829 deletions
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 f3d669b..c8e5804 100644
--- a/src/test/kotlin/dev/dnpm/etl/processor/input/MtbFileRestControllerTest.kt
+++ b/src/test/kotlin/dev/dnpm/etl/processor/input/MtbFileRestControllerTest.kt
@@ -22,14 +22,11 @@ package dev.dnpm.etl.processor.input
import com.fasterxml.jackson.databind.ObjectMapper
import dev.dnpm.etl.processor.ArgProvider
import dev.dnpm.etl.processor.CustomMediaType
-import dev.dnpm.etl.processor.consent.ConsentEvaluation
import dev.dnpm.etl.processor.consent.ConsentEvaluator
import dev.dnpm.etl.processor.consent.TtpConsentStatus
import dev.dnpm.etl.processor.input.Dnpm21MtbFile.Companion.buildMtb
import dev.dnpm.etl.processor.services.RequestProcessor
import dev.pcvolkmer.mv64e.mtb.*
-import java.time.Instant
-import java.util.*
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
@@ -50,134 +47,148 @@ 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
+import java.time.Instant
+import java.util.*
@ExtendWith(MockitoExtension::class)
class MtbFileRestControllerTest {
- private val objectMapper = ObjectMapper()
+ private val objectMapper = ObjectMapper()
- @Nested
- inner class RequestsForDnpmDataModel21 {
+ @Nested
+ inner class RequestsForDnpmDataModel21 {
- private lateinit var mockMvc: MockMvc
+ private lateinit var mockMvc: MockMvc
- private lateinit var requestProcessor: RequestProcessor
- private lateinit var consentEvaluator: ConsentEvaluator
+ private lateinit var requestProcessor: RequestProcessor
- @BeforeEach
- fun setup(@Mock requestProcessor: RequestProcessor, @Mock consentEvaluator: ConsentEvaluator) {
- this.requestProcessor = requestProcessor
- this.consentEvaluator = consentEvaluator
- val controller = MtbFileRestController(requestProcessor, consentEvaluator)
- this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build()
- }
+ @BeforeEach
+ fun setup(@Mock requestProcessor: RequestProcessor) {
+ this.requestProcessor = requestProcessor
+ val controller = MtbFileRestController(requestProcessor)
+ this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build()
+ }
- @Test
- fun shouldRespondPostRequest() {
- val mtbFileContent =
- ClassPathResource("mv64e-mtb-fake-patient.json")
- .inputStream
- .readAllBytes()
- .toString(Charsets.UTF_8)
+ @Test
+ fun shouldRespondPostRequest() {
+ val mtbFileContent =
+ ClassPathResource("mv64e-mtb-fake-patient.json")
+ .inputStream
+ .readAllBytes()
+ .toString(Charsets.UTF_8)
- mockMvc
- .post("/mtb") {
- content = mtbFileContent
- contentType = CustomMediaType.APPLICATION_VND_DNPM_V2_MTB_JSON
- }
- .andExpect { status { isAccepted() } }
+ whenever { requestProcessor.processMtbFile(any<Mtb>()) }.thenReturn(true)
- verify(requestProcessor, times(1)).processMtbFile(any<Mtb>())
- }
+ mockMvc
+ .post("/mtb") {
+ content = mtbFileContent
+ contentType = CustomMediaType.APPLICATION_VND_DNPM_V2_MTB_JSON
+ }
+ .andExpect { status { isAccepted() } }
- @ParameterizedTest
- @ArgumentsSource(Dnpm21MtbFile::class)
- fun shouldProcessPostRequest(mtb: Mtb) {
- mockMvc
- .post("/mtbfile") {
- content = objectMapper.writeValueAsString(mtb)
- contentType = CustomMediaType.APPLICATION_VND_DNPM_V2_MTB_JSON
- }
- .andExpect { status { isAccepted() } }
+ verify(requestProcessor, times(1)).processMtbFile(any<Mtb>())
+ }
- }
+ @ParameterizedTest
+ @ArgumentsSource(Dnpm21MtbFile::class)
+ fun shouldProcessPostRequest(mtb: Mtb) {
+ whenever { requestProcessor.processMtbFile(any<Mtb>()) }.thenReturn(true)
- @ParameterizedTest
- @ValueSource(
- strings =
- [
- "/mtbfile",
- "/mtbfile/etl/patient-record",
- "/mtb",
- "/mtb/etl/patient-record",
- "/api/mtbfile",
- "/api/mtbfile/etl/patient-record",
- "/api/mtb",
- "/api/mtb/etl/patient-record",
- ]
- )
- fun shouldAcceptPostRequests(url: String) {
- val mtb =
- buildMtb(
- MvhMetadata.builder()
- .modelProjectConsent(
- ModelProjectConsent.builder()
- .provisions(
- listOf(
- Provision.builder()
- .date(Date())
- .type(ConsentProvision.PERMIT)
- .purpose(ModelProjectConsentPurpose.SEQUENCING)
- .build()
- )
- )
- .build()
- )
- .build()
- )
+ mockMvc
+ .post("/mtbfile") {
+ content = objectMapper.writeValueAsString(mtb)
+ contentType = CustomMediaType.APPLICATION_VND_DNPM_V2_MTB_JSON
+ }
+ .andExpect { status { isAccepted() } }
+ }
- mockMvc
- .post(url) {
- content = objectMapper.writeValueAsString(mtb)
- contentType = CustomMediaType.APPLICATION_VND_DNPM_V2_MTB_JSON
- }
- .andExpect { status { isAccepted() } }
- }
+ @Test
+ fun shouldNotAcceptInvalidPostRequest() {
+ mockMvc
+ .post("/mtbfile") {
+ content = "{}"
+ contentType = CustomMediaType.APPLICATION_VND_DNPM_V2_MTB_JSON
+ }
+ .andExpect { status { isBadRequest() } }
+ }
- @Test
- fun shouldProcessDeleteRequest() {
- mockMvc.delete("/mtbfile/TEST_12345678").andExpect { status { isAccepted() } }
+ @ParameterizedTest
+ @ValueSource(
+ strings =
+ [
+ "/mtbfile",
+ "/mtbfile/etl/patient-record",
+ "/mtb",
+ "/mtb/etl/patient-record",
+ "/api/mtbfile",
+ "/api/mtbfile/etl/patient-record",
+ "/api/mtb",
+ "/api/mtb/etl/patient-record",
+ ]
+ )
+ fun shouldAcceptPostRequests(url: String) {
+ val mtb =
+ buildMtb(
+ MvhMetadata.builder()
+ .modelProjectConsent(
+ ModelProjectConsent.builder()
+ .provisions(
+ listOf(
+ Provision.builder()
+ .date(Date())
+ .type(ConsentProvision.PERMIT)
+ .purpose(ModelProjectConsentPurpose.SEQUENCING)
+ .build()
+ )
+ )
+ .build()
+ )
+ .build()
+ )
- verify(requestProcessor, times(1))
- .processDeletion(
- anyValueClass(),
- org.mockito.kotlin.eq(TtpConsentStatus.UNKNOWN_CHECK_FILE),
- )
- verify(consentEvaluator, times(0)).check(any<Mtb>())
- }
+ whenever { requestProcessor.processMtbFile(any<Mtb>()) }.thenReturn(true)
+
+ mockMvc
+ .post(url) {
+ content = objectMapper.writeValueAsString(mtb)
+ contentType = CustomMediaType.APPLICATION_VND_DNPM_V2_MTB_JSON
+ }
+ .andExpect { status { isAccepted() } }
+ }
+
+ @Test
+ fun shouldProcessDeleteRequest() {
+ mockMvc.delete("/mtbfile/TEST_12345678").andExpect { status { isAccepted() } }
- @ParameterizedTest
- @ValueSource(
- strings =
- [
- "/mtbfile/TEST_12345678",
- "/mtbfile/etl/patient-record/TEST_12345678",
- "/mtbfile/etl/patient/TEST_12345678",
- "/mtb/TEST_12345678",
- "/mtb/etl/patient-record/TEST_12345678",
- "/mtb/etl/patient/TEST_12345678",
- "/api/mtbfile/TEST_12345678",
- "/api/mtbfile/etl/patient-record/TEST_12345678",
- "/api/mtbfile/etl/patient/TEST_12345678",
- "/api/mtb/TEST_12345678",
- "/api/mtb/etl/patient-record/TEST_12345678",
- "/api/mtb/etl/patient/TEST_12345678",
- ]
- )
- fun shouldAcceptDeleteRequests(url: String) {
- mockMvc.delete(url).andExpect { status { isAccepted() } }
+ verify(requestProcessor, times(1))
+ .processDeletion(
+ anyValueClass(),
+ org.mockito.kotlin.eq(TtpConsentStatus.UNKNOWN_CHECK_FILE),
+ )
+ }
+
+ @ParameterizedTest
+ @ValueSource(
+ strings =
+ [
+ "/mtbfile/TEST_12345678",
+ "/mtbfile/etl/patient-record/TEST_12345678",
+ "/mtbfile/etl/patient/TEST_12345678",
+ "/mtb/TEST_12345678",
+ "/mtb/etl/patient-record/TEST_12345678",
+ "/mtb/etl/patient/TEST_12345678",
+ "/api/mtbfile/TEST_12345678",
+ "/api/mtbfile/etl/patient-record/TEST_12345678",
+ "/api/mtbfile/etl/patient/TEST_12345678",
+ "/api/mtb/TEST_12345678",
+ "/api/mtb/etl/patient-record/TEST_12345678",
+ "/api/mtb/etl/patient/TEST_12345678",
+ ]
+ )
+ fun shouldAcceptDeleteRequests(url: String) {
+ mockMvc.delete(url).andExpect { status { isAccepted() } }
+ }
}
- }
}
class Dnpm21MtbFile :
@@ -234,26 +245,26 @@ class Dnpm21MtbFile :
),
) {
- companion object {
- fun buildMtb(metadata: MvhMetadata?): Mtb {
- return Mtb.builder()
- .patient(
- Patient.builder()
- .id("TEST_12345678")
- .birthDate(Date.from(Instant.parse("2000-08-08T12:34:56Z")))
- .gender(GenderCoding.builder().code(GenderCodingCode.MALE).build())
- .build()
- )
- .metadata(metadata)
- .episodesOfCare(
- listOf(
- MtbEpisodeOfCare.builder()
- .id("1")
- .patient(Reference.builder().id("TEST_12345678").build())
- .build()
- )
- )
- .build()
+ companion object {
+ fun buildMtb(metadata: MvhMetadata?): Mtb {
+ return Mtb.builder()
+ .patient(
+ Patient.builder()
+ .id("TEST_12345678")
+ .birthDate(Date.from(Instant.parse("2000-08-08T12:34:56Z")))
+ .gender(GenderCoding.builder().code(GenderCodingCode.MALE).build())
+ .build()
+ )
+ .metadata(metadata)
+ .episodesOfCare(
+ listOf(
+ MtbEpisodeOfCare.builder()
+ .id("1")
+ .patient(Reference.builder().id("TEST_12345678").build())
+ .build()
+ )
+ )
+ .build()
+ }
}
- }
}
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 afa6872..70df248 100644
--- a/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt
+++ b/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt
@@ -20,10 +20,7 @@
package dev.dnpm.etl.processor.services
import com.fasterxml.jackson.databind.ObjectMapper
-import dev.dnpm.etl.processor.Fingerprint
-import dev.dnpm.etl.processor.PatientId
-import dev.dnpm.etl.processor.PatientPseudonym
-import dev.dnpm.etl.processor.Tan
+import dev.dnpm.etl.processor.*
import dev.dnpm.etl.processor.config.AppConfigProperties
import dev.dnpm.etl.processor.consent.TtpConsentStatus
import dev.dnpm.etl.processor.monitoring.Request
@@ -35,10 +32,7 @@ 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 java.time.Instant
-import java.util.*
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Nested
@@ -52,761 +46,779 @@ import org.mockito.kotlin.anyValueClass
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)
class RequestProcessorTest {
- private lateinit var pseudonymizeService: PseudonymizeService
- private lateinit var transformationService: TransformationService
- private lateinit var sender: MtbFileSender
- private lateinit var requestService: RequestService
- private lateinit var applicationEventPublisher: ApplicationEventPublisher
- private lateinit var appConfigProperties: AppConfigProperties
- private lateinit var consentProcessor: ConsentProcessor
- private lateinit var requestProcessor: RequestProcessor
-
- @BeforeEach
- fun setup(
- @Mock pseudonymizeService: PseudonymizeService,
- @Mock transformationService: TransformationService,
- @Mock sender: RestMtbFileSender,
- @Mock requestService: RequestService,
- @Mock applicationEventPublisher: ApplicationEventPublisher,
- @Mock consentProcessor: ConsentProcessor,
- ) {
- this.pseudonymizeService = pseudonymizeService
- this.transformationService = transformationService
- this.sender = sender
- this.requestService = requestService
- this.applicationEventPublisher = applicationEventPublisher
- this.appConfigProperties = AppConfigProperties()
- this.consentProcessor = consentProcessor
-
- val objectMapper = ObjectMapper()
-
- requestProcessor =
- RequestProcessor(
- pseudonymizeService,
- transformationService,
- sender,
- requestService,
- objectMapper,
- applicationEventPublisher,
- appConfigProperties,
- consentProcessor,
- )
- }
-
- @Test
- fun testShouldSendMtbFileDuplicationAndSaveUnknownRequestStatusAtFirst() {
- doAnswer {
- Request(
- 1L,
- randomRequestId(),
- PatientPseudonym("TEST_12345678901"),
- PatientId("P1"),
- Fingerprint("6vkiti5bk6ikwifpajpt7cygmd3dvw54d6lwfhzlynb3pqtzferq"),
- RequestType.MTB_FILE,
- SubmissionType.TEST,
- RequestStatus.SUCCESS,
- Tan.empty(),
- Instant.parse("2023-08-08T02:00:00Z"),
- )
- }
- .whenever(requestService)
- .lastMtbFileRequestForPatientPseudonym(anyValueClass())
+ private lateinit var pseudonymizeService: PseudonymizeService
+ private lateinit var transformationService: TransformationService
+ private lateinit var sender: MtbFileSender
+ private lateinit var requestService: RequestService
+ private lateinit var applicationEventPublisher: ApplicationEventPublisher
+ private lateinit var appConfigProperties: AppConfigProperties
+ private lateinit var consentProcessor: ConsentProcessor
+ private lateinit var requestProcessor: RequestProcessor
- doAnswer { false }
- .whenever(requestService)
- .isLastRequestWithKnownStatusDeletion(anyValueClass())
+ @BeforeEach
+ fun setup(
+ @Mock pseudonymizeService: PseudonymizeService,
+ @Mock transformationService: TransformationService,
+ @Mock sender: RestMtbFileSender,
+ @Mock requestService: RequestService,
+ @Mock applicationEventPublisher: ApplicationEventPublisher,
+ @Mock consentProcessor: ConsentProcessor,
+ ) {
+ this.pseudonymizeService = pseudonymizeService
+ this.transformationService = transformationService
+ this.sender = sender
+ this.requestService = requestService
+ this.applicationEventPublisher = applicationEventPublisher
+ this.appConfigProperties = AppConfigProperties()
+ this.consentProcessor = consentProcessor
+
+ val objectMapper = ObjectMapper()
+
+ requestProcessor =
+ RequestProcessor(
+ pseudonymizeService,
+ transformationService,
+ sender,
+ requestService,
+ objectMapper,
+ applicationEventPublisher,
+ appConfigProperties,
+ consentProcessor,
+ )
+ }
- doAnswer { it.arguments[0] as String }
- .whenever(pseudonymizeService)
- .patientPseudonym(anyValueClass())
+ @Test
+ fun testShouldSendMtbFileDuplicationAndSaveUnknownRequestStatusAtFirst() {
+ doAnswer {
+ Request(
+ 1L,
+ randomRequestId(),
+ PatientPseudonym("TEST_12345678901"),
+ PatientId("P1"),
+ Fingerprint("6vkiti5bk6ikwifpajpt7cygmd3dvw54d6lwfhzlynb3pqtzferq"),
+ RequestType.MTB_FILE,
+ SubmissionType.TEST,
+ RequestStatus.SUCCESS,
+ Tan.empty(),
+ Instant.parse("2023-08-08T02:00:00Z"),
+ )
+ }
+ .whenever(requestService)
+ .lastMtbFileRequestForPatientPseudonym(anyValueClass())
+
+ doAnswer { false }
+ .whenever(requestService)
+ .isLastRequestWithKnownStatusDeletion(anyValueClass())
+
+ doAnswer { it.arguments[0] as String }
+ .whenever(pseudonymizeService)
+ .patientPseudonym(anyValueClass())
+
+ doAnswer { it.arguments[0] }.whenever(transformationService).transform(any<Mtb>())
+
+ whenever(consentProcessor.consentGatedCheckAndTryEmbedding(any())).thenReturn(true)
+
+ val mtbFile =
+ Mtb.builder()
+ .patient(Patient.builder().id("123").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()
- doAnswer { it.arguments[0] }.whenever(transformationService).transform(any<Mtb>())
+ this.requestProcessor.processMtbFile(mtbFile)
- whenever(consentProcessor.consentGatedCheckAndTryEmbedding(any())).thenReturn(true)
+ val requestCaptor = argumentCaptor<Request>()
+ verify(requestService, times(1)).save(requestCaptor.capture())
+ assertThat(requestCaptor.firstValue).isNotNull
+ assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.UNKNOWN)
+ }
- val mtbFile =
- Mtb.builder()
- .patient(Patient.builder().id("123").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()
- )
+ @Test
+ fun testShouldDetectMtbFileDuplicationAndSendDuplicationEvent() {
+ doAnswer {
+ Request(
+ 1L,
+ randomRequestId(),
+ PatientPseudonym("TEST_12345678901"),
+ PatientId("P1"),
+ Fingerprint("4gcjwtjjtcczybsljxepdfpkaeusvd7g3vogfqpmphyffyzfx7dq"),
+ RequestType.MTB_FILE,
+ SubmissionType.TEST,
+ RequestStatus.SUCCESS,
+ Tan.empty(),
+ Instant.parse("2023-08-08T02:00:00Z"),
)
- .build()
-
- this.requestProcessor.processMtbFile(mtbFile)
-
- val requestCaptor = argumentCaptor<Request>()
- verify(requestService, times(1)).save(requestCaptor.capture())
- assertThat(requestCaptor.firstValue).isNotNull
- assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.UNKNOWN)
- }
-
- @Test
- fun testShouldDetectMtbFileDuplicationAndSendDuplicationEvent() {
- doAnswer {
- Request(
- 1L,
- randomRequestId(),
- PatientPseudonym("TEST_12345678901"),
- PatientId("P1"),
- Fingerprint("4gcjwtjjtcczybsljxepdfpkaeusvd7g3vogfqpmphyffyzfx7dq"),
- RequestType.MTB_FILE,
- SubmissionType.TEST,
- RequestStatus.SUCCESS,
- Tan.empty(),
- Instant.parse("2023-08-08T02:00:00Z"),
- )
}
- .whenever(requestService)
- .lastMtbFileRequestForPatientPseudonym(anyValueClass())
+ .whenever(requestService)
+ .lastMtbFileRequestForPatientPseudonym(anyValueClass())
+
+ doAnswer { false }
+ .whenever(requestService)
+ .isLastRequestWithKnownStatusDeletion(anyValueClass())
+
+ doAnswer { it.arguments[0] as String }
+ .whenever(pseudonymizeService)
+ .patientPseudonym(anyValueClass())
+
+ doAnswer { it.arguments[0] }.whenever(transformationService).transform(any<Mtb>())
+
+ whenever(consentProcessor.consentGatedCheckAndTryEmbedding(any())).thenReturn(true)
+
+ val mtbFile =
+ Mtb.builder()
+ .patient(Patient.builder().id("123").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()
- doAnswer { false }
- .whenever(requestService)
- .isLastRequestWithKnownStatusDeletion(anyValueClass())
+ this.requestProcessor.processMtbFile(mtbFile)
- doAnswer { it.arguments[0] as String }
- .whenever(pseudonymizeService)
- .patientPseudonym(anyValueClass())
+ val eventCaptor = argumentCaptor<ResponseEvent>()
+ verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
+ assertThat(eventCaptor.firstValue).isNotNull
+ assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.DUPLICATION)
+ }
- doAnswer { it.arguments[0] }.whenever(transformationService).transform(any<Mtb>())
+ @Test
+ fun testShouldSendMtbFileAndSendSuccessEvent() {
+ doAnswer {
+ Request(
+ 1L,
+ randomRequestId(),
+ PatientPseudonym("TEST_12345678901"),
+ PatientId("P1"),
+ Fingerprint("different"),
+ RequestType.MTB_FILE,
+ SubmissionType.TEST,
+ RequestStatus.SUCCESS,
+ Tan.empty(),
+ Instant.parse("2023-08-08T02:00:00Z"),
+ )
+ }
+ .whenever(requestService)
+ .lastMtbFileRequestForPatientPseudonym(anyValueClass())
+
+ doAnswer { false }
+ .whenever(requestService)
+ .isLastRequestWithKnownStatusDeletion(anyValueClass())
+
+ doAnswer { MtbFileSender.Response(status = RequestStatus.SUCCESS) }
+ .whenever(sender)
+ .send(any<DnpmV2MtbFileRequest>())
+
+ doAnswer { it.arguments[0] as String }
+ .whenever(pseudonymizeService)
+ .patientPseudonym(anyValueClass())
+
+ doAnswer { it.arguments[0] }.whenever(transformationService).transform(any<Mtb>())
+
+ whenever(consentProcessor.consentGatedCheckAndTryEmbedding(any())).thenReturn(true)
+
+ val mtbFile =
+ Mtb.builder()
+ .patient(Patient.builder().id("123").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()
- whenever(consentProcessor.consentGatedCheckAndTryEmbedding(any())).thenReturn(true)
+ this.requestProcessor.processMtbFile(mtbFile)
- val mtbFile =
- Mtb.builder()
- .patient(Patient.builder().id("123").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")))
+ val eventCaptor = argumentCaptor<ResponseEvent>()
+ verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
+ assertThat(eventCaptor.firstValue).isNotNull
+ assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.SUCCESS)
+ }
+
+ @Test
+ fun testShouldSendMtbFileAndSendErrorEvent() {
+ doAnswer {
+ Request(
+ 1L,
+ randomRequestId(),
+ PatientPseudonym("TEST_12345678901"),
+ PatientId("P1"),
+ Fingerprint("different"),
+ RequestType.MTB_FILE,
+ SubmissionType.TEST,
+ RequestStatus.SUCCESS,
+ Tan.empty(),
+ Instant.parse("2023-08-08T02:00:00Z"),
+ )
+ }
+ .whenever(requestService)
+ .lastMtbFileRequestForPatientPseudonym(anyValueClass())
+
+ doAnswer { false }
+ .whenever(requestService)
+ .isLastRequestWithKnownStatusDeletion(anyValueClass())
+
+ doAnswer { MtbFileSender.Response(status = RequestStatus.ERROR) }
+ .whenever(sender)
+ .send(any<DnpmV2MtbFileRequest>())
+
+ doAnswer { it.arguments[0] as String }
+ .whenever(pseudonymizeService)
+ .patientPseudonym(anyValueClass())
+
+ doAnswer { "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2" }
+ .whenever(pseudonymizeService)
+ .genomDeTan(anyValueClass())
+
+ doAnswer { it.arguments[0] }.whenever(transformationService).transform(any<Mtb>())
+
+ whenever(consentProcessor.consentGatedCheckAndTryEmbedding(any())).thenReturn(true)
+
+ val mtbFile =
+ Mtb.builder()
+ .patient(Patient.builder().id("123").build())
+ .metadata(
+ MvhMetadata.builder()
+ .modelProjectConsent(
+ ModelProjectConsent.builder()
+ .provisions(
+ listOf(
+ Provision.builder()
+ .type(ConsentProvision.PERMIT)
+ .purpose(ModelProjectConsentPurpose.SEQUENCING)
+ .build()
+ )
+ )
.build()
)
.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()
+
+ this.requestProcessor.processMtbFile(mtbFile)
+
+ val eventCaptor = argumentCaptor<ResponseEvent>()
+ verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
+ assertThat(eventCaptor.firstValue).isNotNull
+ assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.ERROR)
+ }
+
+ @Test
+ fun testShouldSendMtbFileAdditionIfInitialFileWasAccepted() {
+
+ // One successful and accepted and one blocked initial
+ val lastRequests =
+ listOf(
+ Request(
+ 1L,
+ randomRequestId(),
+ PatientPseudonym("TEST_12345678901"),
+ PatientId("P1"),
+ Fingerprint("initial"),
+ RequestType.MTB_FILE,
+ SubmissionType.INITIAL,
+ RequestStatus.SUCCESS,
+ Tan.empty(),
+ Instant.parse("2026-01-05T09:00:00Z"),
+ submissionAccepted = true,
+ ),
+ Request(
+ 2L,
+ randomRequestId(),
+ PatientPseudonym("TEST_12345678901"),
+ PatientId("P1"),
+ Fingerprint("blocked_initial"),
+ RequestType.MTB_FILE,
+ SubmissionType.INITIAL,
+ RequestStatus.BLOCKED_INITIAL,
+ Tan.empty(),
+ Instant.parse("2026-01-05T10:00:00Z"),
+ submissionAccepted = false,
+ ),
)
- .build()
-
- this.requestProcessor.processMtbFile(mtbFile)
-
- val eventCaptor = argumentCaptor<ResponseEvent>()
- verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
- assertThat(eventCaptor.firstValue).isNotNull
- assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.DUPLICATION)
- }
-
- @Test
- fun testShouldSendMtbFileAndSendSuccessEvent() {
- doAnswer {
- Request(
- 1L,
- randomRequestId(),
- PatientPseudonym("TEST_12345678901"),
- PatientId("P1"),
- Fingerprint("different"),
- RequestType.MTB_FILE,
- SubmissionType.TEST,
- RequestStatus.SUCCESS,
- Tan.empty(),
- Instant.parse("2023-08-08T02:00:00Z"),
- )
- }
- .whenever(requestService)
- .lastMtbFileRequestForPatientPseudonym(anyValueClass())
- doAnswer { false }
- .whenever(requestService)
- .isLastRequestWithKnownStatusDeletion(anyValueClass())
+ doAnswer { lastRequests }
+ .whenever(requestService)
+ .allRequestsByPatientPseudonym(anyValueClass())
- doAnswer { MtbFileSender.Response(status = RequestStatus.SUCCESS) }
- .whenever(sender)
- .send(any<DnpmV2MtbFileRequest>())
+ doAnswer { false }
+ .whenever(requestService)
+ .isLastRequestWithKnownStatusDeletion(anyValueClass())
- doAnswer { it.arguments[0] as String }
- .whenever(pseudonymizeService)
- .patientPseudonym(anyValueClass())
+ doAnswer { MtbFileSender.Response(status = RequestStatus.SUCCESS) }
+ .whenever(sender)
+ .send(any<DnpmV2MtbFileRequest>())
- doAnswer { it.arguments[0] }.whenever(transformationService).transform(any<Mtb>())
+ doAnswer { it.arguments[0] as String }
+ .whenever(pseudonymizeService)
+ .patientPseudonym(anyValueClass())
- whenever(consentProcessor.consentGatedCheckAndTryEmbedding(any())).thenReturn(true)
+ doAnswer { "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2" }
+ .whenever(pseudonymizeService)
+ .genomDeTan(anyValueClass())
- val mtbFile =
- Mtb.builder()
- .patient(Patient.builder().id("123").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()
- )
+ doAnswer { it.arguments[0] }.whenever(transformationService).transform(any<Mtb>())
+
+ whenever(consentProcessor.consentGatedCheckAndTryEmbedding(any())).thenReturn(true)
+
+ requestProcessor =
+ RequestProcessor(
+ pseudonymizeService,
+ transformationService,
+ sender,
+ requestService,
+ ObjectMapper(),
+ applicationEventPublisher,
+ AppConfigProperties(postInitialSubmissionBlock = true),
+ consentProcessor,
)
- .build()
-
- this.requestProcessor.processMtbFile(mtbFile)
-
- val eventCaptor = argumentCaptor<ResponseEvent>()
- verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
- assertThat(eventCaptor.firstValue).isNotNull
- assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.SUCCESS)
- }
-
- @Test
- fun testShouldSendMtbFileAndSendErrorEvent() {
- doAnswer {
- Request(
- 1L,
- randomRequestId(),
- PatientPseudonym("TEST_12345678901"),
- PatientId("P1"),
- Fingerprint("different"),
- RequestType.MTB_FILE,
- SubmissionType.TEST,
- RequestStatus.SUCCESS,
- Tan.empty(),
- Instant.parse("2023-08-08T02:00:00Z"),
- )
- }
- .whenever(requestService)
- .lastMtbFileRequestForPatientPseudonym(anyValueClass())
-
- doAnswer { false }
- .whenever(requestService)
- .isLastRequestWithKnownStatusDeletion(anyValueClass())
-
- doAnswer { MtbFileSender.Response(status = RequestStatus.ERROR) }
- .whenever(sender)
- .send(any<DnpmV2MtbFileRequest>())
-
- doAnswer { it.arguments[0] as String }
- .whenever(pseudonymizeService)
- .patientPseudonym(anyValueClass())
-
- doAnswer { "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2" }
- .whenever(pseudonymizeService)
- .genomDeTan(anyValueClass())
-
- doAnswer { it.arguments[0] }.whenever(transformationService).transform(any<Mtb>())
-
- whenever(consentProcessor.consentGatedCheckAndTryEmbedding(any())).thenReturn(true)
-
- val mtbFile =
- Mtb.builder()
- .patient(Patient.builder().id("123").build())
- .metadata(
- MvhMetadata.builder()
- .modelProjectConsent(
- ModelProjectConsent.builder()
- .provisions(
- listOf(
- Provision.builder()
- .type(ConsentProvision.PERMIT)
- .purpose(ModelProjectConsentPurpose.SEQUENCING)
- .build()
- )
+
+ val mtbFile =
+ Mtb.builder()
+ .patient(Patient.builder().id("123").build())
+ .metadata(MvhMetadata())
+ .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()
- )
- .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()
+ .build()
- this.requestProcessor.processMtbFile(mtbFile)
+ this.requestProcessor.processMtbFile(mtbFile)
- val eventCaptor = argumentCaptor<ResponseEvent>()
- verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
- assertThat(eventCaptor.firstValue).isNotNull
- assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.ERROR)
- }
+ val requestCaptor = argumentCaptor<DnpmV2MtbFileRequest>()
+ verify(sender, times(1)).send(requestCaptor.capture())
+ assertThat(requestCaptor.firstValue).isNotNull
+ assertThat(requestCaptor.firstValue.content.metadata.type).isEqualTo(MvhSubmissionType.ADDITION)
+ assertThat(requestCaptor.firstValue.content.metadata.transferTan).isEqualTo("f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2")
- @Test
- fun testShouldSendMtbFileAdditionIfInitialFileWasAccepted() {
+ val eventCaptor = argumentCaptor<ResponseEvent>()
+ verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
+ assertThat(eventCaptor.firstValue).isNotNull
+ assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.SUCCESS)
+ }
- // One successful and accepted and one blocked initial
- val lastRequests =
- listOf(
- Request(
- 1L,
- randomRequestId(),
- PatientPseudonym("TEST_12345678901"),
- PatientId("P1"),
- Fingerprint("initial"),
- RequestType.MTB_FILE,
- SubmissionType.INITIAL,
- RequestStatus.SUCCESS,
- Tan.empty(),
- Instant.parse("2026-01-05T09:00:00Z"),
- submissionAccepted = true,
- ),
- Request(
- 2L,
- randomRequestId(),
- PatientPseudonym("TEST_12345678901"),
- PatientId("P1"),
- Fingerprint("blocked_initial"),
- RequestType.MTB_FILE,
- SubmissionType.INITIAL,
- RequestStatus.BLOCKED_INITIAL,
- Tan.empty(),
- Instant.parse("2026-01-05T10:00:00Z"),
- submissionAccepted = false,
- ),
+ @Test
+ fun testShouldSendDeleteRequestAndSaveUnknownRequestStatusAtFirst() {
+ doAnswer { "PSEUDONYM" }.whenever(pseudonymizeService).patientPseudonym(anyValueClass())
+
+ doAnswer { MtbFileSender.Response(status = RequestStatus.UNKNOWN) }
+ .whenever(sender)
+ .send(any<DeleteRequest>())
+
+ this.requestProcessor.processDeletion(
+ TEST_PATIENT_ID,
+ isConsented = TtpConsentStatus.UNKNOWN_CHECK_FILE,
)
- doAnswer { lastRequests }
- .whenever(requestService)
- .allRequestsByPatientPseudonym(anyValueClass())
+ val requestCaptor = argumentCaptor<Request>()
+ verify(requestService, times(1)).save(requestCaptor.capture())
+ assertThat(requestCaptor.firstValue).isNotNull
+ assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.UNKNOWN)
+ }
- doAnswer { false }
- .whenever(requestService)
- .isLastRequestWithKnownStatusDeletion(anyValueClass())
+ @Test
+ fun testShouldSendDeleteRequestAndSendSuccessEvent() {
+ doAnswer { "PSEUDONYM" }.whenever(pseudonymizeService).patientPseudonym(anyValueClass())
- doAnswer { MtbFileSender.Response(status = RequestStatus.SUCCESS) }
- .whenever(sender)
- .send(any<DnpmV2MtbFileRequest>())
+ doAnswer { MtbFileSender.Response(status = RequestStatus.SUCCESS) }
+ .whenever(sender)
+ .send(any<DeleteRequest>())
- doAnswer { it.arguments[0] as String }
- .whenever(pseudonymizeService)
- .patientPseudonym(anyValueClass())
+ this.requestProcessor.processDeletion(
+ TEST_PATIENT_ID,
+ isConsented = TtpConsentStatus.UNKNOWN_CHECK_FILE,
+ )
- doAnswer { "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2" }
- .whenever(pseudonymizeService)
- .genomDeTan(anyValueClass())
+ val eventCaptor = argumentCaptor<ResponseEvent>()
+ verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
+ assertThat(eventCaptor.firstValue).isNotNull
+ assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.SUCCESS)
+ }
- doAnswer { it.arguments[0] }.whenever(transformationService).transform(any<Mtb>())
+ @Test
+ fun testShouldSendRequestWithoutConsent() {
+ doAnswer { "PSEUDONYM" }.whenever(pseudonymizeService).patientPseudonym(anyValueClass())
+
+ doAnswer { MtbFileSender.Response(status = RequestStatus.SUCCESS) }
+ .whenever(sender)
+ .send(any<DnpmV2MtbFileRequest>())
+
+ doAnswer { it.arguments.first() }
+ .whenever(transformationService)
+ .transform(any<Mtb>())
+
+ val mtbFile =
+ Mtb.builder()
+ .patient(Patient.builder().id("123").build())
+ .metadata(MvhMetadata())
+ .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()
+
+ this.requestProcessor.processMtbFile(
+ mtbFile,
+ randomRequestId(),
+ )
+
+ val eventCaptor = argumentCaptor<ResponseEvent>()
+ verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
+ assertThat(eventCaptor.firstValue).isNotNull
+ assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.SUCCESS)
+ }
+
+ @Test
+ fun testShouldSendDeleteRequestAndSendErrorEvent() {
+ doAnswer { "PSEUDONYM" }.whenever(pseudonymizeService).patientPseudonym(anyValueClass())
- whenever(consentProcessor.consentGatedCheckAndTryEmbedding(any())).thenReturn(true)
+ doAnswer { MtbFileSender.Response(status = RequestStatus.ERROR) }
+ .whenever(sender)
+ .send(any<DeleteRequest>())
- requestProcessor =
- RequestProcessor(
- pseudonymizeService,
- transformationService,
- sender,
- requestService,
- ObjectMapper(),
- applicationEventPublisher,
- AppConfigProperties(postInitialSubmissionBlock = true),
- consentProcessor,
+ this.requestProcessor.processDeletion(
+ TEST_PATIENT_ID,
+ isConsented = TtpConsentStatus.UNKNOWN_CHECK_FILE,
)
- val mtbFile =
- Mtb.builder()
- .patient(Patient.builder().id("123").build())
- .metadata(MvhMetadata())
- .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()
-
- this.requestProcessor.processMtbFile(mtbFile)
-
- val requestCaptor = argumentCaptor<DnpmV2MtbFileRequest>()
- verify(sender, times(1)).send(requestCaptor.capture())
- assertThat(requestCaptor.firstValue).isNotNull
- assertThat(requestCaptor.firstValue.content.metadata.type).isEqualTo(MvhSubmissionType.ADDITION)
- assertThat(requestCaptor.firstValue.content.metadata.transferTan).isEqualTo("f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2")
-
- val eventCaptor = argumentCaptor<ResponseEvent>()
- verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
- assertThat(eventCaptor.firstValue).isNotNull
- assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.SUCCESS)
- }
-
- @Test
- fun testShouldSendDeleteRequestAndSaveUnknownRequestStatusAtFirst() {
- doAnswer { "PSEUDONYM" }.whenever(pseudonymizeService).patientPseudonym(anyValueClass())
-
- doAnswer { MtbFileSender.Response(status = RequestStatus.UNKNOWN) }
- .whenever(sender)
- .send(any<DeleteRequest>())
-
- this.requestProcessor.processDeletion(
- TEST_PATIENT_ID,
- isConsented = TtpConsentStatus.UNKNOWN_CHECK_FILE,
- )
-
- val requestCaptor = argumentCaptor<Request>()
- verify(requestService, times(1)).save(requestCaptor.capture())
- assertThat(requestCaptor.firstValue).isNotNull
- assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.UNKNOWN)
- }
-
- @Test
- fun testShouldSendDeleteRequestAndSendSuccessEvent() {
- doAnswer { "PSEUDONYM" }.whenever(pseudonymizeService).patientPseudonym(anyValueClass())
-
- doAnswer { MtbFileSender.Response(status = RequestStatus.SUCCESS) }
- .whenever(sender)
- .send(any<DeleteRequest>())
-
- this.requestProcessor.processDeletion(
- TEST_PATIENT_ID,
- isConsented = TtpConsentStatus.UNKNOWN_CHECK_FILE,
- )
-
- val eventCaptor = argumentCaptor<ResponseEvent>()
- verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
- assertThat(eventCaptor.firstValue).isNotNull
- assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.SUCCESS)
- }
+ val eventCaptor = argumentCaptor<ResponseEvent>()
+ verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
+ assertThat(eventCaptor.firstValue).isNotNull
+ assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.ERROR)
+ }
@Test
- fun testShouldSendRequestWithoutConsent() {
- doAnswer { "PSEUDONYM" }.whenever(pseudonymizeService).patientPseudonym(anyValueClass())
-
- doAnswer { MtbFileSender.Response(status = RequestStatus.SUCCESS) }
- .whenever(sender)
- .send(any<DnpmV2MtbFileRequest>())
-
- doAnswer { it.arguments.first() }
- .whenever(transformationService)
- .transform(any<Mtb>())
-
- val mtbFile =
- Mtb.builder()
- .patient(Patient.builder().id("123").build())
- .metadata(MvhMetadata())
- .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()
+ fun testShouldSendDeleteRequestWithPseudonymErrorAndSaveErrorRequestStatus() {
+ doThrow(RuntimeException()).whenever(pseudonymizeService).patientPseudonym(anyValueClass())
+
+ this.requestProcessor.processDeletion(
+ TEST_PATIENT_ID,
+ isConsented = TtpConsentStatus.UNKNOWN_CHECK_FILE,
+ )
+
+ val requestCaptor = argumentCaptor<Request>()
+ verify(requestService, times(1)).save(requestCaptor.capture())
+ assertThat(requestCaptor.firstValue).isNotNull
+ assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.ERROR)
+ }
+
+ @Test
+ fun testShouldNotDetectMtbFileDuplicationIfDuplicationNotConfigured() {
+ this.appConfigProperties.duplicationDetection = false
+
+ doAnswer { it.arguments[0] as String }
+ .whenever(pseudonymizeService)
+ .patientPseudonym(anyValueClass())
+
+ doAnswer { it.arguments[0] }.whenever(transformationService).transform(any<Mtb>())
+
+ doAnswer { MtbFileSender.Response(status = RequestStatus.SUCCESS) }
+ .whenever(sender)
+ .send(any<DnpmV2MtbFileRequest>())
+
+ whenever(consentProcessor.consentGatedCheckAndTryEmbedding(any())).thenReturn(true)
+
+ val mtbFile =
+ Mtb.builder()
+ .patient(Patient.builder().id("123").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()
+
+ this.requestProcessor.processMtbFile(mtbFile)
+
+ val eventCaptor = argumentCaptor<ResponseEvent>()
+ verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
+ assertThat(eventCaptor.firstValue).isNotNull
+ assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.SUCCESS)
+ }
+
+ @Test
+ fun testShouldSaveRequestWithGenomDeTan() {
+
+ doAnswer { false }
+ .whenever(requestService)
+ .isLastRequestWithKnownStatusDeletion(anyValueClass())
+
+ doAnswer { MtbFileSender.Response(status = RequestStatus.SUCCESS) }
+ .whenever(sender)
+ .send(any<DnpmV2MtbFileRequest>())
+
+ doAnswer { it.arguments[0] as String }
+ .whenever(pseudonymizeService)
+ .patientPseudonym(anyValueClass())
+
+ doAnswer { "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2" }
+ .whenever(pseudonymizeService)
+ .genomDeTan(anyValueClass())
+
+ doAnswer { it.arguments[0] }.whenever(transformationService).transform(any<Mtb>())
+
+ whenever(consentProcessor.consentGatedCheckAndTryEmbedding(any())).thenReturn(true)
+
+ requestProcessor =
+ RequestProcessor(
+ pseudonymizeService,
+ transformationService,
+ sender,
+ requestService,
+ ObjectMapper(),
+ applicationEventPublisher,
+ AppConfigProperties(postInitialSubmissionBlock = true),
+ consentProcessor,
)
- .build()
-
- this.requestProcessor.processMtbFile(
- mtbFile,
- randomRequestId(),
- )
-
- val eventCaptor = argumentCaptor<ResponseEvent>()
- verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
- assertThat(eventCaptor.firstValue).isNotNull
- assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.SUCCESS)
- }
-
- @Test
- fun testShouldSendDeleteRequestAndSendErrorEvent() {
- doAnswer { "PSEUDONYM" }.whenever(pseudonymizeService).patientPseudonym(anyValueClass())
-
- doAnswer { MtbFileSender.Response(status = RequestStatus.ERROR) }
- .whenever(sender)
- .send(any<DeleteRequest>())
-
- this.requestProcessor.processDeletion(
- TEST_PATIENT_ID,
- isConsented = TtpConsentStatus.UNKNOWN_CHECK_FILE,
- )
-
- val eventCaptor = argumentCaptor<ResponseEvent>()
- verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
- assertThat(eventCaptor.firstValue).isNotNull
- assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.ERROR)
- }
-
- @Test
- fun testShouldSendDeleteRequestWithPseudonymErrorAndSaveErrorRequestStatus() {
- doThrow(RuntimeException()).whenever(pseudonymizeService).patientPseudonym(anyValueClass())
-
- this.requestProcessor.processDeletion(
- TEST_PATIENT_ID,
- isConsented = TtpConsentStatus.UNKNOWN_CHECK_FILE,
- )
-
- val requestCaptor = argumentCaptor<Request>()
- verify(requestService, times(1)).save(requestCaptor.capture())
- assertThat(requestCaptor.firstValue).isNotNull
- assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.ERROR)
- }
-
- @Test
- fun testShouldNotDetectMtbFileDuplicationIfDuplicationNotConfigured() {
- this.appConfigProperties.duplicationDetection = false
-
- doAnswer { it.arguments[0] as String }
- .whenever(pseudonymizeService)
- .patientPseudonym(anyValueClass())
-
- doAnswer { it.arguments[0] }.whenever(transformationService).transform(any<Mtb>())
-
- doAnswer { MtbFileSender.Response(status = RequestStatus.SUCCESS) }
- .whenever(sender)
- .send(any<DnpmV2MtbFileRequest>())
-
- whenever(consentProcessor.consentGatedCheckAndTryEmbedding(any())).thenReturn(true)
-
- val mtbFile =
- Mtb.builder()
- .patient(Patient.builder().id("123").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()
+
+ val mtbFile =
+ Mtb.builder()
+ .patient(Patient.builder().id("123").build())
+ .metadata(MvhMetadata())
+ .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()
+ .build()
- this.requestProcessor.processMtbFile(mtbFile)
+ this.requestProcessor.processMtbFile(mtbFile)
- val eventCaptor = argumentCaptor<ResponseEvent>()
- verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
- assertThat(eventCaptor.firstValue).isNotNull
- assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.SUCCESS)
- }
+ val requestCaptor = argumentCaptor<Request>()
+ verify(requestService, times(1)).save(requestCaptor.capture())
+ assertThat(requestCaptor.firstValue).isNotNull
+ assertThat(requestCaptor.firstValue.tan).isEqualTo(Tan("f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2"))
+ }
- @Test
- fun testShouldSaveRequestWithGenomDeTan() {
-
- doAnswer { false }
- .whenever(requestService)
- .isLastRequestWithKnownStatusDeletion(anyValueClass())
-
- doAnswer { MtbFileSender.Response(status = RequestStatus.SUCCESS) }
- .whenever(sender)
- .send(any<DnpmV2MtbFileRequest>())
-
- doAnswer { it.arguments[0] as String }
- .whenever(pseudonymizeService)
- .patientPseudonym(anyValueClass())
-
- doAnswer { "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2" }
- .whenever(pseudonymizeService)
- .genomDeTan(anyValueClass())
-
- doAnswer { it.arguments[0] }.whenever(transformationService).transform(any<Mtb>())
-
- whenever(consentProcessor.consentGatedCheckAndTryEmbedding(any())).thenReturn(true)
-
- requestProcessor =
- RequestProcessor(
- pseudonymizeService,
- transformationService,
- sender,
- requestService,
- ObjectMapper(),
- applicationEventPublisher,
- AppConfigProperties(postInitialSubmissionBlock = true),
- consentProcessor,
- )
+ @Nested
+ inner class WithInitialSubmissionBlock {
+
+ private lateinit var pseudonymizeService: PseudonymizeService
+ private lateinit var transformationService: TransformationService
+ private lateinit var sender: MtbFileSender
+ private lateinit var requestService: RequestService
+ private lateinit var applicationEventPublisher: ApplicationEventPublisher
+ private lateinit var appConfigProperties: AppConfigProperties
+ private lateinit var consentProcessor: ConsentProcessor
+ private lateinit var requestProcessor: RequestProcessor
+
+ @BeforeEach
+ fun setup(
+ @Mock pseudonymizeService: PseudonymizeService,
+ @Mock transformationService: TransformationService,
+ @Mock sender: RestMtbFileSender,
+ @Mock requestService: RequestService,
+ @Mock applicationEventPublisher: ApplicationEventPublisher,
+ @Mock consentProcessor: ConsentProcessor,
+ ) {
+ this.pseudonymizeService = pseudonymizeService
+ this.transformationService = transformationService
+ this.sender = sender
+ this.requestService = requestService
+ this.applicationEventPublisher = applicationEventPublisher
+ this.appConfigProperties = AppConfigProperties()
+ this.consentProcessor = consentProcessor
+
+ val objectMapper = ObjectMapper()
+
+ requestProcessor =
+ RequestProcessor(
+ pseudonymizeService,
+ transformationService,
+ sender,
+ requestService,
+ objectMapper,
+ applicationEventPublisher,
+ appConfigProperties,
+ consentProcessor,
+ )
+ }
+
+ @Test
+ fun testShouldNotSendMtbFileIfInitialFileWasSent() {
- val mtbFile =
- Mtb.builder()
- .patient(Patient.builder().id("123").build())
- .metadata(MvhMetadata())
- .episodesOfCare(
+ // One failed attempt and one successful but not accepted
+ val lastRequests =
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()
+ Request(
+ 1L,
+ randomRequestId(),
+ PatientPseudonym("TEST_12345678901"),
+ PatientId("P1"),
+ Fingerprint("initial"),
+ RequestType.MTB_FILE,
+ SubmissionType.INITIAL,
+ RequestStatus.ERROR,
+ Tan.empty(),
+ Instant.parse("2026-01-05T09:00:00Z"),
+ submissionAccepted = false,
+ ),
+ Request(
+ 2L,
+ randomRequestId(),
+ PatientPseudonym("TEST_12345678901"),
+ PatientId("P1"),
+ Fingerprint("blocked_initial"),
+ RequestType.MTB_FILE,
+ SubmissionType.INITIAL,
+ RequestStatus.SUCCESS,
+ Tan.empty(),
+ Instant.parse("2026-01-05T10:00:00Z"),
+ submissionAccepted = false,
+ ),
)
- )
- .build()
- this.requestProcessor.processMtbFile(mtbFile)
+ doAnswer { lastRequests }
+ .whenever(requestService)
+ .allRequestsByPatientPseudonym(anyValueClass())
- val requestCaptor = argumentCaptor<Request>()
- verify(requestService, times(1)).save(requestCaptor.capture())
- assertThat(requestCaptor.firstValue).isNotNull
- assertThat(requestCaptor.firstValue.tan).isEqualTo(Tan("f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2"))
- }
+ doAnswer { it.arguments[0] as String }
+ .whenever(pseudonymizeService)
+ .patientPseudonym(anyValueClass())
- @Nested
- inner class WithInitialSubmissionBlock {
+ doAnswer { it.arguments[0] }.whenever(transformationService).transform(any<Mtb>())
- private lateinit var pseudonymizeService: PseudonymizeService
- private lateinit var transformationService: TransformationService
- private lateinit var sender: MtbFileSender
- private lateinit var requestService: RequestService
- private lateinit var applicationEventPublisher: ApplicationEventPublisher
- private lateinit var appConfigProperties: AppConfigProperties
- private lateinit var consentProcessor: ConsentProcessor
- private lateinit var requestProcessor: RequestProcessor
+ whenever(consentProcessor.consentGatedCheckAndTryEmbedding(any())).thenReturn(true)
- @BeforeEach
- fun setup(
- @Mock pseudonymizeService: PseudonymizeService,
- @Mock transformationService: TransformationService,
- @Mock sender: RestMtbFileSender,
- @Mock requestService: RequestService,
- @Mock applicationEventPublisher: ApplicationEventPublisher,
- @Mock consentProcessor: ConsentProcessor,
- ) {
- this.pseudonymizeService = pseudonymizeService
- this.transformationService = transformationService
- this.sender = sender
- this.requestService = requestService
- this.applicationEventPublisher = applicationEventPublisher
- this.appConfigProperties = AppConfigProperties()
- this.consentProcessor = consentProcessor
-
- val objectMapper = ObjectMapper()
-
- requestProcessor =
- RequestProcessor(
- pseudonymizeService,
- transformationService,
- sender,
- requestService,
- objectMapper,
- applicationEventPublisher,
- appConfigProperties,
- consentProcessor,
- )
+ requestProcessor =
+ RequestProcessor(
+ pseudonymizeService,
+ transformationService,
+ sender,
+ requestService,
+ ObjectMapper(),
+ applicationEventPublisher,
+ AppConfigProperties(postInitialSubmissionBlock = true),
+ consentProcessor,
+ )
+
+ val mtbFile =
+ Mtb.builder()
+ .patient(Patient.builder().id("123").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()
+
+ this.requestProcessor.processMtbFile(mtbFile)
+
+ val requestCaptor = argumentCaptor<Request>()
+ verify(requestService, times(1)).save(requestCaptor.capture())
+ assertThat(requestCaptor.firstValue).isNotNull
+ assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.BLOCKED_INITIAL)
+
+ verify(applicationEventPublisher, times(0)).publishEvent(any())
+ verify(sender, times(0)).send(any<DnpmV2MtbFileRequest>())
+ }
}
@Test
- fun testShouldNotSendMtbFileIfInitialFileWasSent() {
-
- // One failed attempt and one successful but not accepted
- val lastRequests =
- listOf(
- Request(
- 1L,
- randomRequestId(),
- PatientPseudonym("TEST_12345678901"),
- PatientId("P1"),
- Fingerprint("initial"),
- RequestType.MTB_FILE,
- SubmissionType.INITIAL,
- RequestStatus.ERROR,
- Tan.empty(),
- Instant.parse("2026-01-05T09:00:00Z"),
- submissionAccepted = false,
- ),
- Request(
- 2L,
- randomRequestId(),
- PatientPseudonym("TEST_12345678901"),
- PatientId("P1"),
- Fingerprint("blocked_initial"),
- RequestType.MTB_FILE,
- SubmissionType.INITIAL,
- RequestStatus.SUCCESS,
- Tan.empty(),
- Instant.parse("2026-01-05T10:00:00Z"),
- submissionAccepted = false,
- ),
- )
-
- doAnswer { lastRequests }
- .whenever(requestService)
- .allRequestsByPatientPseudonym(anyValueClass())
-
- doAnswer { it.arguments[0] as String }
- .whenever(pseudonymizeService)
- .patientPseudonym(anyValueClass())
-
- doAnswer { it.arguments[0] }.whenever(transformationService).transform(any<Mtb>())
-
- whenever(consentProcessor.consentGatedCheckAndTryEmbedding(any())).thenReturn(true)
-
- requestProcessor =
- RequestProcessor(
- pseudonymizeService,
- transformationService,
- sender,
- requestService,
- ObjectMapper(),
- applicationEventPublisher,
- AppConfigProperties(postInitialSubmissionBlock = true),
- consentProcessor,
- )
-
- val mtbFile =
- Mtb.builder()
- .patient(Patient.builder().id("123").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()
-
- this.requestProcessor.processMtbFile(mtbFile)
-
- val requestCaptor = argumentCaptor<Request>()
- verify(requestService, times(1)).save(requestCaptor.capture())
- assertThat(requestCaptor.firstValue).isNotNull
- assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.BLOCKED_INITIAL)
-
- verify(applicationEventPublisher, times(0)).publishEvent(any())
- verify(sender, times(0)).send(any<DnpmV2MtbFileRequest>())
+ fun shouldCatchExceptionsWhenProcessingMtbFileAndSaveError() {
+ val invalidMtbFile = Mtb.builder().build()
+
+ val success = this.requestProcessor.processMtbFile(invalidMtbFile)
+
+ assertThat(success).isFalse()
+
+ verify(sender, times(0)).send(any<DnpmV2MtbFileRequest>())
+
+ val requestCaptor = argumentCaptor<Request>()
+ verify(requestService, times(1)).save(requestCaptor.capture())
+ assertThat(requestCaptor.firstValue).isInstanceOf(Request::class.java)
+ assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.ERROR)
}
- }
- companion object {
- val TEST_PATIENT_ID = PatientId("TEST_12345678901")
- }
+ companion object {
+ val TEST_PATIENT_ID = PatientId("TEST_12345678901")
+ }
}