summaryrefslogtreecommitdiff
path: root/src/test/kotlin/dev/dnpm
diff options
context:
space:
mode:
authorPaul-Christian Volkmer2026-01-06 16:34:12 +0100
committerGitHub2026-01-06 15:34:12 +0000
commit7be91444a867774362eb5b57bdd246fb50189e7d (patch)
tree6a325575bf19e4016ead259a92803b110071eb4f /src/test/kotlin/dev/dnpm
parent2a106a49d91699d0699af1134c41a43b942b85e8 (diff)
feat: block further initial submissions (#232)
Diffstat (limited to 'src/test/kotlin/dev/dnpm')
-rw-r--r--src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt232
-rw-r--r--src/test/kotlin/dev/dnpm/etl/processor/services/RequestServiceTest.kt11
-rw-r--r--src/test/kotlin/dev/dnpm/etl/processor/services/ResponseProcessorTest.kt2
-rw-r--r--src/test/kotlin/dev/dnpm/etl/processor/services/TransformationServiceTest.kt11
4 files changed, 253 insertions, 3 deletions
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 4bd3fc1..851c1a1 100644
--- a/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt
+++ b/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt
@@ -28,6 +28,7 @@ import dev.dnpm.etl.processor.consent.TtpConsentStatus
import dev.dnpm.etl.processor.monitoring.Request
import dev.dnpm.etl.processor.monitoring.RequestStatus
import dev.dnpm.etl.processor.monitoring.RequestType
+import dev.dnpm.etl.processor.monitoring.SubmissionType
import dev.dnpm.etl.processor.output.DeleteRequest
import dev.dnpm.etl.processor.output.DnpmV2MtbFileRequest
import dev.dnpm.etl.processor.output.MtbFileSender
@@ -39,6 +40,7 @@ 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
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.Mock
@@ -104,6 +106,7 @@ class RequestProcessorTest {
PatientId("P1"),
Fingerprint("6vkiti5bk6ikwifpajpt7cygmd3dvw54d6lwfhzlynb3pqtzferq"),
RequestType.MTB_FILE,
+ SubmissionType.TEST,
RequestStatus.SUCCESS,
Instant.parse("2023-08-08T02:00:00Z"),
)
@@ -159,6 +162,7 @@ class RequestProcessorTest {
PatientId("P1"),
Fingerprint("4gcjwtjjtcczybsljxepdfpkaeusvd7g3vogfqpmphyffyzfx7dq"),
RequestType.MTB_FILE,
+ SubmissionType.TEST,
RequestStatus.SUCCESS,
Instant.parse("2023-08-08T02:00:00Z"),
)
@@ -214,6 +218,7 @@ class RequestProcessorTest {
PatientId("P1"),
Fingerprint("different"),
RequestType.MTB_FILE,
+ SubmissionType.TEST,
RequestStatus.SUCCESS,
Instant.parse("2023-08-08T02:00:00Z"),
)
@@ -273,6 +278,7 @@ class RequestProcessorTest {
PatientId("P1"),
Fingerprint("different"),
RequestType.MTB_FILE,
+ SubmissionType.TEST,
RequestStatus.SUCCESS,
Instant.parse("2023-08-08T02:00:00Z"),
)
@@ -339,6 +345,102 @@ class RequestProcessorTest {
}
@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,
+ 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,
+ Instant.parse("2026-01-05T10:00:00Z"),
+ submissionAccepted = false,
+ ),
+ )
+
+ doAnswer { lastRequests }
+ .whenever(requestService)
+ .allRequestsByPatientPseudonym(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)
+
+ requestProcessor =
+ RequestProcessor(
+ pseudonymizeService,
+ transformationService,
+ sender,
+ requestService,
+ ObjectMapper(),
+ applicationEventPublisher,
+ AppConfigProperties(postInitialSubmissionBlock = true),
+ consentProcessor,
+ )
+
+ 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)
+
+ 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())
@@ -452,6 +554,136 @@ class RequestProcessorTest {
assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.SUCCESS)
}
+ @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() {
+
+ // 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,
+ 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,
+ 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>())
+ }
+ }
+
companion object {
val TEST_PATIENT_ID = PatientId("TEST_12345678901")
}
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 bc0286c..fdb7578 100644
--- a/src/test/kotlin/dev/dnpm/etl/processor/services/RequestServiceTest.kt
+++ b/src/test/kotlin/dev/dnpm/etl/processor/services/RequestServiceTest.kt
@@ -24,6 +24,7 @@ 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.monitoring.SubmissionType
import java.time.Instant
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.BeforeEach
@@ -51,6 +52,7 @@ class RequestServiceTest {
PatientId("PX"),
Fingerprint("dummy"),
RequestType.MTB_FILE,
+ SubmissionType.TEST,
RequestStatus.SUCCESS,
Instant.parse("2023-08-08T02:00:00Z"),
)
@@ -72,6 +74,7 @@ class RequestServiceTest {
PatientId("P1"),
Fingerprint("0123456789abcdef1"),
RequestType.MTB_FILE,
+ SubmissionType.TEST,
RequestStatus.WARNING,
Instant.parse("2023-07-07T00:00:00Z"),
),
@@ -82,6 +85,7 @@ class RequestServiceTest {
PatientId("P1"),
Fingerprint("0123456789abcdefd"),
RequestType.DELETE,
+ SubmissionType.TEST,
RequestStatus.WARNING,
Instant.parse("2023-07-07T02:00:00Z"),
),
@@ -92,6 +96,7 @@ class RequestServiceTest {
PatientId("P1"),
Fingerprint("0123456789abcdef1"),
RequestType.MTB_FILE,
+ SubmissionType.TEST,
RequestStatus.UNKNOWN,
Instant.parse("2023-08-11T00:00:00Z"),
),
@@ -113,6 +118,7 @@ class RequestServiceTest {
PatientId("P1"),
Fingerprint("0123456789abcdef1"),
RequestType.MTB_FILE,
+ SubmissionType.TEST,
RequestStatus.WARNING,
Instant.parse("2023-07-07T00:00:00Z"),
),
@@ -123,6 +129,7 @@ class RequestServiceTest {
PatientId("P1"),
Fingerprint("0123456789abcdef1"),
RequestType.MTB_FILE,
+ SubmissionType.TEST,
RequestStatus.WARNING,
Instant.parse("2023-07-07T02:00:00Z"),
),
@@ -133,6 +140,7 @@ class RequestServiceTest {
PatientId("P1"),
Fingerprint("0123456789abcdef1"),
RequestType.MTB_FILE,
+ SubmissionType.TEST,
RequestStatus.UNKNOWN,
Instant.parse("2023-08-11T00:00:00Z"),
),
@@ -154,6 +162,7 @@ class RequestServiceTest {
PatientId("P1"),
Fingerprint("0123456789abcdef1"),
RequestType.DELETE,
+ SubmissionType.TEST,
RequestStatus.SUCCESS,
Instant.parse("2023-07-07T02:00:00Z"),
),
@@ -164,6 +173,7 @@ class RequestServiceTest {
PatientId("P2"),
Fingerprint("0123456789abcdef2"),
RequestType.MTB_FILE,
+ SubmissionType.TEST,
RequestStatus.WARNING,
Instant.parse("2023-08-08T00:00:00Z"),
),
@@ -200,6 +210,7 @@ class RequestServiceTest {
PatientId("P1"),
Fingerprint("0123456789abcdef1"),
RequestType.DELETE,
+ SubmissionType.TEST,
RequestStatus.SUCCESS,
Instant.parse("2023-07-07T02:00:00Z"),
)
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 16a5791..804b91c 100644
--- a/src/test/kotlin/dev/dnpm/etl/processor/services/ResponseProcessorTest.kt
+++ b/src/test/kotlin/dev/dnpm/etl/processor/services/ResponseProcessorTest.kt
@@ -23,6 +23,7 @@ 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
+import dev.dnpm.etl.processor.monitoring.SubmissionType
import java.time.Instant
import java.util.*
import org.assertj.core.api.Assertions.assertThat
@@ -52,6 +53,7 @@ class ResponseProcessorTest {
PatientId("1"),
Fingerprint("dummyfingerprint"),
RequestType.MTB_FILE,
+ SubmissionType.TEST,
RequestStatus.UNKNOWN,
)
diff --git a/src/test/kotlin/dev/dnpm/etl/processor/services/TransformationServiceTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/services/TransformationServiceTest.kt
index a4af214..3af5097 100644
--- a/src/test/kotlin/dev/dnpm/etl/processor/services/TransformationServiceTest.kt
+++ b/src/test/kotlin/dev/dnpm/etl/processor/services/TransformationServiceTest.kt
@@ -24,11 +24,11 @@ import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.node.ObjectNode
import dev.dnpm.etl.processor.config.JacksonConfig
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.Test
-import java.time.Instant
-import java.util.*
class TransformationServiceTest {
@@ -149,7 +149,12 @@ class TransformationServiceTest {
)
.build()
val consent = ConsentProcessorTest.getDummyGenomDeConsent()
- val jsonNode = ObjectMapper().readValue(FhirContext.forR4().newJsonParser().encodeToString(consent), ObjectNode::class.java)
+ val jsonNode =
+ ObjectMapper()
+ .readValue(
+ FhirContext.forR4().newJsonParser().encodeToString(consent),
+ ObjectNode::class.java,
+ )
mvhMetadata.researchConsents = mutableListOf()
mvhMetadata.researchConsents.add(MvhMetadata.ResearchConsent.from(jsonNode))