summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul-Christian Volkmer2023-08-08 14:50:12 +0200
committerPaul-Christian Volkmer2023-08-08 14:57:31 +0200
commitbcc23f6b14436ba6f4585a583da6c236df68e25a (patch)
treef2af7ea0b92d8f8b124a9b467da29d539a262598 /src
parent1fc09d691ea01415a21f1192cc7b1cf25bc0ac14 (diff)
Add RequestService to handle access to requests
Diffstat (limited to 'src')
-rw-r--r--src/main/kotlin/dev/dnpm/etl/processor/services/RequestProcessor.kt17
-rw-r--r--src/main/kotlin/dev/dnpm/etl/processor/services/RequestService.kt56
-rw-r--r--src/test/kotlin/dev/dnpm/etl/processor/services/RequestServiceIntegrationTest.kt131
-rw-r--r--src/test/kotlin/dev/dnpm/etl/processor/services/RequestServiceTest.kt205
4 files changed, 402 insertions, 7 deletions
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 bdf2827..e04e568 100644
--- a/src/main/kotlin/dev/dnpm/etl/processor/services/RequestProcessor.kt
+++ b/src/main/kotlin/dev/dnpm/etl/processor/services/RequestProcessor.kt
@@ -21,7 +21,10 @@ package dev.dnpm.etl.processor.services
import com.fasterxml.jackson.databind.ObjectMapper
import de.ukw.ccc.bwhc.dto.MtbFile
-import dev.dnpm.etl.processor.monitoring.*
+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.output.MtbFileSender
import dev.dnpm.etl.processor.pseudonym.PseudonymizeService
import org.apache.commons.codec.binary.Base32
@@ -35,7 +38,7 @@ import java.util.*
class RequestProcessor(
private val pseudonymizeService: PseudonymizeService,
private val senders: List<MtbFileSender>,
- private val requestRepository: RequestRepository,
+ private val requestService: RequestService,
private val objectMapper: ObjectMapper,
private val statisticsUpdateProducer: Sinks.Many<Any>
) {
@@ -46,7 +49,7 @@ class RequestProcessor(
val pid = mtbFile.patient.id
val pseudonymized = pseudonymizeService.pseudonymize(mtbFile)
- val allRequests = requestRepository.findAllByPatientIdOrderByProcessedAtDesc(pseudonymized.patient.id)
+ val allRequests = requestService.allRequestsByPatientPseudonym(pseudonymized.patient.id)
val lastMtbFileRequestForPatient = allRequests
.filter { it.type == RequestType.MTB_FILE }
@@ -55,7 +58,7 @@ class RequestProcessor(
val isLastRequestDeletion = allRequests.firstOrNull()?.type == RequestType.DELETE
if (null != lastMtbFileRequestForPatient && lastMtbFileRequestForPatient.fingerprint == fingerprint(mtbFile) && !isLastRequestDeletion) {
- requestRepository.save(
+ requestService.save(
Request(
patientId = pseudonymized.patient.id,
pid = pid,
@@ -99,7 +102,7 @@ class RequestProcessor(
RequestStatus.UNKNOWN
}
- requestRepository.save(
+ requestService.save(
Request(
uuid = request.requestId,
patientId = request.mtbFile.patient.id,
@@ -165,7 +168,7 @@ class RequestProcessor(
RequestStatus.UNKNOWN
}
- requestRepository.save(
+ requestService.save(
Request(
uuid = requestId,
patientId = patientPseudonym,
@@ -181,7 +184,7 @@ class RequestProcessor(
)
)
} catch (e: Exception) {
- requestRepository.save(
+ requestService.save(
Request(
uuid = requestId,
patientId = "???",
diff --git a/src/main/kotlin/dev/dnpm/etl/processor/services/RequestService.kt b/src/main/kotlin/dev/dnpm/etl/processor/services/RequestService.kt
new file mode 100644
index 0000000..0f69910
--- /dev/null
+++ b/src/main/kotlin/dev/dnpm/etl/processor/services/RequestService.kt
@@ -0,0 +1,56 @@
+/*
+ * This file is part of ETL-Processor
+ *
+ * Copyright (c) 2023 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 <https://www.gnu.org/licenses/>.
+ */
+
+package dev.dnpm.etl.processor.services
+
+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 org.springframework.stereotype.Service
+
+@Service
+class RequestService(
+ private val requestRepository: RequestRepository
+) {
+
+ fun save(request: Request) = requestRepository.save(request)
+
+ fun allRequestsByPatientPseudonym(patientPseudonym: String) = requestRepository
+ .findAllByPatientIdOrderByProcessedAtDesc(patientPseudonym)
+
+ fun lastMtbFileRequestForPatientPseudonym(patientPseudonym: String) =
+ Companion.lastMtbFileRequestForPatientPseudonym(allRequestsByPatientPseudonym(patientPseudonym))
+
+ fun isLastRequestDeletion(patientPseudonym: String) =
+ Companion.isLastRequestDeletion(allRequestsByPatientPseudonym(patientPseudonym))
+
+ companion object {
+
+ fun lastMtbFileRequestForPatientPseudonym(allRequests: List<Request>) = allRequests
+ .filter { it.type == RequestType.MTB_FILE }
+ .sortedByDescending { it.processedAt }
+ .firstOrNull { it.status == RequestStatus.SUCCESS || it.status == RequestStatus.WARNING }
+
+ fun isLastRequestDeletion(allRequests: List<Request>) = allRequests
+ .maxByOrNull { it.processedAt }?.type == RequestType.DELETE
+
+ }
+
+} \ No newline at end of file
diff --git a/src/test/kotlin/dev/dnpm/etl/processor/services/RequestServiceIntegrationTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/services/RequestServiceIntegrationTest.kt
new file mode 100644
index 0000000..d71e011
--- /dev/null
+++ b/src/test/kotlin/dev/dnpm/etl/processor/services/RequestServiceIntegrationTest.kt
@@ -0,0 +1,131 @@
+/*
+ * This file is part of ETL-Processor
+ *
+ * Copyright (c) 2023 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 <https://www.gnu.org/licenses/>.
+ */
+
+package dev.dnpm.etl.processor.services
+
+import dev.dnpm.etl.processor.AbstractTestcontainerTest
+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 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.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.context.junit.jupiter.SpringExtension
+import org.springframework.transaction.annotation.Transactional
+import org.testcontainers.junit.jupiter.Testcontainers
+import java.time.Instant
+import java.util.*
+
+@Testcontainers
+@ExtendWith(SpringExtension::class)
+@SpringBootTest
+@Transactional
+class RequestServiceIntegrationTest : AbstractTestcontainerTest() {
+
+ private lateinit var requestRepository: RequestRepository
+
+ private lateinit var requestService: RequestService
+
+ @BeforeEach
+ fun setup(
+ @Autowired requestRepository: RequestRepository
+ ) {
+ this.requestRepository = requestRepository
+ this.requestService = RequestService(requestRepository)
+ }
+
+ @Test
+ fun shouldResultInEmptyRequestList() {
+ val actual = requestService.allRequestsByPatientPseudonym("TEST_12345678901")
+
+ assertThat(actual).isEmpty()
+ }
+
+ private fun setupTestData() {
+ // Prepare DB
+ this.requestRepository.saveAll(
+ listOf(
+ Request(
+ uuid = UUID.randomUUID().toString(),
+ patientId = "TEST_12345678901",
+ pid = "P1",
+ fingerprint = "0123456789abcdef1",
+ type = RequestType.MTB_FILE,
+ status = RequestStatus.SUCCESS,
+ processedAt = Instant.parse("2023-07-07T02:00:00Z")
+ ),
+ // Should be ignored - wrong patient ID -->
+ Request(
+ uuid = UUID.randomUUID().toString(),
+ patientId = "TEST_12345678902",
+ pid = "P2",
+ fingerprint = "0123456789abcdef2",
+ type = RequestType.MTB_FILE,
+ status = RequestStatus.WARNING,
+ processedAt = Instant.parse("2023-08-08T00:00:00Z")
+ ),
+ // <--
+ Request(
+ uuid = UUID.randomUUID().toString(),
+ patientId = "TEST_12345678901",
+ pid = "P2",
+ fingerprint = "0123456789abcdee1",
+ type = RequestType.DELETE,
+ status = RequestStatus.SUCCESS,
+ processedAt = Instant.parse("2023-08-08T02:00:00Z")
+ )
+ )
+ )
+ }
+
+ @Test
+ fun shouldResultInSortedRequestList() {
+ setupTestData()
+
+ val actual = requestService.allRequestsByPatientPseudonym("TEST_12345678901")
+
+ assertThat(actual).hasSize(2)
+ assertThat(actual[0].fingerprint).isEqualTo("0123456789abcdee1")
+ assertThat(actual[1].fingerprint).isEqualTo("0123456789abcdef1")
+ }
+
+ @Test
+ fun shouldReturnDeleteRequestAsLastRequest() {
+ setupTestData()
+
+ val actual = requestService.isLastRequestDeletion("TEST_12345678901")
+
+ assertThat(actual).isTrue()
+ }
+
+ @Test
+ fun shouldReturnLastMtbFileRequest() {
+ setupTestData()
+
+ val actual = requestService.lastMtbFileRequestForPatientPseudonym("TEST_12345678901")
+
+ assertThat(actual).isNotNull
+ assertThat(actual?.fingerprint).isEqualTo("0123456789abcdef1")
+ }
+
+} \ 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
new file mode 100644
index 0000000..3e0a979
--- /dev/null
+++ b/src/test/kotlin/dev/dnpm/etl/processor/services/RequestServiceTest.kt
@@ -0,0 +1,205 @@
+/*
+ * This file is part of ETL-Processor
+ *
+ * Copyright (c) 2023 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 <https://www.gnu.org/licenses/>.
+ */
+
+package dev.dnpm.etl.processor.services
+
+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 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.Mock
+import org.mockito.Mockito.*
+import org.mockito.junit.jupiter.MockitoExtension
+import java.time.Instant
+import java.util.*
+
+@ExtendWith(MockitoExtension::class)
+class RequestServiceTest {
+
+ private lateinit var requestRepository: RequestRepository
+
+ private lateinit var requestService: RequestService
+
+ private fun anyRequest() = any(Request::class.java) ?: Request(
+ id = 0L,
+ uuid = UUID.randomUUID().toString(),
+ patientId = "TEST_dummy",
+ pid = "PX",
+ fingerprint = "dummy",
+ type = RequestType.MTB_FILE,
+ status = RequestStatus.SUCCESS,
+ processedAt = Instant.parse("2023-08-08T02:00:00Z")
+ )
+
+ @BeforeEach
+ fun setup(
+ @Mock requestRepository: RequestRepository
+ ) {
+ this.requestRepository = requestRepository
+ this.requestService = RequestService(requestRepository)
+ }
+
+ @Test
+ fun shouldIndicateLastRequestIsDeleteRequest() {
+ val requests = listOf(
+ Request(
+ id = 1L,
+ uuid = UUID.randomUUID().toString(),
+ patientId = "TEST_12345678901",
+ pid = "P1",
+ fingerprint = "0123456789abcdef1",
+ type = RequestType.DELETE,
+ status = RequestStatus.SUCCESS,
+ processedAt = Instant.parse("2023-08-08T02:00:00Z")
+ ),
+ Request(
+ id = 1L,
+ uuid = UUID.randomUUID().toString(),
+ patientId = "TEST_12345678902",
+ pid = "P2",
+ fingerprint = "0123456789abcdef2",
+ type = RequestType.MTB_FILE,
+ status = RequestStatus.WARNING,
+ processedAt = Instant.parse("2023-08-08T00:00:00Z")
+ )
+ )
+
+ val actual = RequestService.isLastRequestDeletion(requests)
+
+ assertThat(actual).isTrue()
+ }
+
+ @Test
+ fun shouldIndicateLastRequestIsNotDeleteRequest() {
+ val requests = listOf(
+ Request(
+ id = 1L,
+ uuid = UUID.randomUUID().toString(),
+ patientId = "TEST_12345678901",
+ pid = "P1",
+ fingerprint = "0123456789abcdef1",
+ type = RequestType.DELETE,
+ status = RequestStatus.SUCCESS,
+ processedAt = Instant.parse("2023-07-07T02:00:00Z")
+ ),
+ Request(
+ id = 1L,
+ uuid = UUID.randomUUID().toString(),
+ patientId = "TEST_12345678902",
+ pid = "P2",
+ fingerprint = "0123456789abcdef2",
+ type = RequestType.MTB_FILE,
+ status = RequestStatus.WARNING,
+ processedAt = Instant.parse("2023-08-08T00:00:00Z")
+ )
+ )
+
+ val actual = RequestService.isLastRequestDeletion(requests)
+
+ assertThat(actual).isFalse()
+ }
+
+ @Test
+ fun shouldReturnPatientsLastRequest() {
+ val requests = listOf(
+ Request(
+ id = 1L,
+ uuid = UUID.randomUUID().toString(),
+ patientId = "TEST_12345678901",
+ pid = "P1",
+ fingerprint = "0123456789abcdef1",
+ type = RequestType.DELETE,
+ status = RequestStatus.SUCCESS,
+ processedAt = Instant.parse("2023-07-07T02:00:00Z")
+ ),
+ Request(
+ id = 1L,
+ uuid = UUID.randomUUID().toString(),
+ patientId = "TEST_12345678902",
+ pid = "P2",
+ fingerprint = "0123456789abcdef2",
+ type = RequestType.MTB_FILE,
+ status = RequestStatus.WARNING,
+ processedAt = Instant.parse("2023-08-08T00:00:00Z")
+ )
+ )
+
+ val actual = RequestService.lastMtbFileRequestForPatientPseudonym(requests)
+
+ assertThat(actual).isInstanceOf(Request::class.java)
+ assertThat(actual?.fingerprint).isEqualTo("0123456789abcdef2")
+ }
+
+ @Test
+ fun shouldReturnNullIfNoRequests() {
+ val requests = listOf<Request>()
+
+ val actual = RequestService.lastMtbFileRequestForPatientPseudonym(requests)
+
+ assertThat(actual).isNull()
+ }
+
+ @Test
+ fun saveShouldSaveRequestUsingRepository() {
+ doAnswer {
+ val obj = it.arguments[0] as Request
+ obj.copy(id = 1L)
+ }.`when`(requestRepository).save(anyRequest())
+
+ val request = Request(
+ uuid = UUID.randomUUID().toString(),
+ patientId = "TEST_12345678901",
+ pid = "P1",
+ fingerprint = "0123456789abcdef1",
+ type = RequestType.DELETE,
+ status = RequestStatus.SUCCESS,
+ processedAt = Instant.parse("2023-07-07T02:00:00Z")
+ )
+
+ requestService.save(request)
+
+ verify(requestRepository, times(1)).save(anyRequest())
+ }
+
+ @Test
+ fun allRequestsByPatientPseudonymShouldRequestAllRequestsForPatientPseudonym() {
+ requestService.allRequestsByPatientPseudonym("TEST_12345678901")
+
+ verify(requestRepository, times(1)).findAllByPatientIdOrderByProcessedAtDesc(anyString())
+ }
+
+ @Test
+ fun lastMtbFileRequestForPatientPseudonymShouldRequestAllRequestsForPatientPseudonym() {
+ requestService.lastMtbFileRequestForPatientPseudonym("TEST_12345678901")
+
+ verify(requestRepository, times(1)).findAllByPatientIdOrderByProcessedAtDesc(anyString())
+ }
+
+ @Test
+ fun isLastRequestDeletionShouldRequestAllRequestsForPatientPseudonym() {
+ requestService.isLastRequestDeletion("TEST_12345678901")
+
+ verify(requestRepository, times(1)).findAllByPatientIdOrderByProcessedAtDesc(anyString())
+ }
+
+} \ No newline at end of file