From 3039b4b2a7eb7963d0952a28ca5fd26328640223 Mon Sep 17 00:00:00 2001
From: Paul-Christian Volkmer
Date: Tue, 8 Aug 2023 13:23:18 +0200
Subject: Add basic Testcontainers test setup
---
.../etl/processor/AbstractTestcontainerTest.kt | 45 ++++++++++++++++++++++
.../etl/processor/BwhcMapperApplicationTests.kt | 37 ++++++++++++++++++
2 files changed, 82 insertions(+)
create mode 100644 src/test/kotlin/dev/dnpm/etl/processor/AbstractTestcontainerTest.kt
create mode 100644 src/test/kotlin/dev/dnpm/etl/processor/BwhcMapperApplicationTests.kt
(limited to 'src/test/kotlin')
diff --git a/src/test/kotlin/dev/dnpm/etl/processor/AbstractTestcontainerTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/AbstractTestcontainerTest.kt
new file mode 100644
index 0000000..3bd934f
--- /dev/null
+++ b/src/test/kotlin/dev/dnpm/etl/processor/AbstractTestcontainerTest.kt
@@ -0,0 +1,45 @@
+/*
+ * 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 .
+ */
+
+package dev.dnpm.etl.processor
+
+import org.springframework.test.context.DynamicPropertyRegistry
+import org.springframework.test.context.DynamicPropertySource
+import org.testcontainers.containers.PostgreSQLContainer
+import org.testcontainers.junit.jupiter.Container
+
+abstract class AbstractTestcontainerTest {
+
+ companion object {
+ @Container
+ val dbContainer = PostgreSQLContainer("postgres:10-alpine")
+ .withDatabaseName("test")
+ .withUsername("test")
+ .withPassword("test") ?: throw RuntimeException("Failed to create testcontainer!")
+
+ @DynamicPropertySource
+ @JvmStatic
+ fun registerDynamicProperties(registry: DynamicPropertyRegistry) {
+ registry.add("spring.datasource.url", dbContainer::getJdbcUrl)
+ registry.add("spring.datasource.username", dbContainer::getUsername)
+ registry.add("spring.datasource.password", dbContainer::getPassword)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/kotlin/dev/dnpm/etl/processor/BwhcMapperApplicationTests.kt b/src/test/kotlin/dev/dnpm/etl/processor/BwhcMapperApplicationTests.kt
new file mode 100644
index 0000000..efa6a66
--- /dev/null
+++ b/src/test/kotlin/dev/dnpm/etl/processor/BwhcMapperApplicationTests.kt
@@ -0,0 +1,37 @@
+/*
+ * 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 .
+ */
+
+package dev.dnpm.etl.processor
+
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.extension.ExtendWith
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.context.junit.jupiter.SpringExtension
+import org.testcontainers.junit.jupiter.Testcontainers
+
+@Testcontainers
+@ExtendWith(SpringExtension::class)
+@SpringBootTest
+class BwhcMapperApplicationTests : AbstractTestcontainerTest() {
+
+ @Test
+ fun contextLoads() {
+ }
+
+}
--
cgit v1.2.3
From 1fc09d691ea01415a21f1192cc7b1cf25bc0ac14 Mon Sep 17 00:00:00 2001
From: Paul-Christian Volkmer
Date: Tue, 8 Aug 2023 13:34:53 +0200
Subject: Rename test class to match applications main class name
---
.../etl/processor/BwhcMapperApplicationTests.kt | 37 ----------------------
.../etl/processor/EtlProcessorApplicationTests.kt | 37 ++++++++++++++++++++++
2 files changed, 37 insertions(+), 37 deletions(-)
delete mode 100644 src/test/kotlin/dev/dnpm/etl/processor/BwhcMapperApplicationTests.kt
create mode 100644 src/test/kotlin/dev/dnpm/etl/processor/EtlProcessorApplicationTests.kt
(limited to 'src/test/kotlin')
diff --git a/src/test/kotlin/dev/dnpm/etl/processor/BwhcMapperApplicationTests.kt b/src/test/kotlin/dev/dnpm/etl/processor/BwhcMapperApplicationTests.kt
deleted file mode 100644
index efa6a66..0000000
--- a/src/test/kotlin/dev/dnpm/etl/processor/BwhcMapperApplicationTests.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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 .
- */
-
-package dev.dnpm.etl.processor
-
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.extension.ExtendWith
-import org.springframework.boot.test.context.SpringBootTest
-import org.springframework.test.context.junit.jupiter.SpringExtension
-import org.testcontainers.junit.jupiter.Testcontainers
-
-@Testcontainers
-@ExtendWith(SpringExtension::class)
-@SpringBootTest
-class BwhcMapperApplicationTests : AbstractTestcontainerTest() {
-
- @Test
- fun contextLoads() {
- }
-
-}
diff --git a/src/test/kotlin/dev/dnpm/etl/processor/EtlProcessorApplicationTests.kt b/src/test/kotlin/dev/dnpm/etl/processor/EtlProcessorApplicationTests.kt
new file mode 100644
index 0000000..07a201b
--- /dev/null
+++ b/src/test/kotlin/dev/dnpm/etl/processor/EtlProcessorApplicationTests.kt
@@ -0,0 +1,37 @@
+/*
+ * 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 .
+ */
+
+package dev.dnpm.etl.processor
+
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.extension.ExtendWith
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.context.junit.jupiter.SpringExtension
+import org.testcontainers.junit.jupiter.Testcontainers
+
+@Testcontainers
+@ExtendWith(SpringExtension::class)
+@SpringBootTest
+class EtlProcessorApplicationTests : AbstractTestcontainerTest() {
+
+ @Test
+ fun contextLoads() {
+ }
+
+}
--
cgit v1.2.3
From bcc23f6b14436ba6f4585a583da6c236df68e25a Mon Sep 17 00:00:00 2001
From: Paul-Christian Volkmer
Date: Tue, 8 Aug 2023 14:50:12 +0200
Subject: Add RequestService to handle access to requests
---
.../services/RequestServiceIntegrationTest.kt | 131 +++++++++++++
.../etl/processor/services/RequestServiceTest.kt | 205 +++++++++++++++++++++
2 files changed, 336 insertions(+)
create mode 100644 src/test/kotlin/dev/dnpm/etl/processor/services/RequestServiceIntegrationTest.kt
create mode 100644 src/test/kotlin/dev/dnpm/etl/processor/services/RequestServiceTest.kt
(limited to 'src/test/kotlin')
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 .
+ */
+
+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 .
+ */
+
+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()
+
+ 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
--
cgit v1.2.3
From 4051b5094ca8daaa844803d2725b4094f3eed096 Mon Sep 17 00:00:00 2001
From: Paul-Christian Volkmer
Date: Tue, 8 Aug 2023 14:58:10 +0200
Subject: Keep database testcontainer alive until all tests are done
---
.../kotlin/dev/dnpm/etl/processor/AbstractTestcontainerTest.kt | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
(limited to 'src/test/kotlin')
diff --git a/src/test/kotlin/dev/dnpm/etl/processor/AbstractTestcontainerTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/AbstractTestcontainerTest.kt
index 3bd934f..13b57d0 100644
--- a/src/test/kotlin/dev/dnpm/etl/processor/AbstractTestcontainerTest.kt
+++ b/src/test/kotlin/dev/dnpm/etl/processor/AbstractTestcontainerTest.kt
@@ -28,7 +28,7 @@ abstract class AbstractTestcontainerTest {
companion object {
@Container
- val dbContainer = PostgreSQLContainer("postgres:10-alpine")
+ val dbContainer = CustomPostgreSQLContainer("postgres:10-alpine")
.withDatabaseName("test")
.withUsername("test")
.withPassword("test") ?: throw RuntimeException("Failed to create testcontainer!")
@@ -42,4 +42,10 @@ abstract class AbstractTestcontainerTest {
}
}
+}
+
+class CustomPostgreSQLContainer(dockerImageName: String) : PostgreSQLContainer(dockerImageName) {
+ override fun stop() {
+ // Keep Testcontainer alive until JVM destroys it
+ }
}
\ No newline at end of file
--
cgit v1.2.3
From b75328b74d361b7afd6197a5b240f5f76ce2c5e0 Mon Sep 17 00:00:00 2001
From: Paul-Christian Volkmer
Date: Tue, 8 Aug 2023 15:16:58 +0200
Subject: Move integration tests into own source-set
---
.../etl/processor/AbstractTestcontainerTest.kt | 51 --------
.../etl/processor/EtlProcessorApplicationTests.kt | 37 ------
.../services/RequestServiceIntegrationTest.kt | 131 ---------------------
3 files changed, 219 deletions(-)
delete mode 100644 src/test/kotlin/dev/dnpm/etl/processor/AbstractTestcontainerTest.kt
delete mode 100644 src/test/kotlin/dev/dnpm/etl/processor/EtlProcessorApplicationTests.kt
delete mode 100644 src/test/kotlin/dev/dnpm/etl/processor/services/RequestServiceIntegrationTest.kt
(limited to 'src/test/kotlin')
diff --git a/src/test/kotlin/dev/dnpm/etl/processor/AbstractTestcontainerTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/AbstractTestcontainerTest.kt
deleted file mode 100644
index 13b57d0..0000000
--- a/src/test/kotlin/dev/dnpm/etl/processor/AbstractTestcontainerTest.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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 .
- */
-
-package dev.dnpm.etl.processor
-
-import org.springframework.test.context.DynamicPropertyRegistry
-import org.springframework.test.context.DynamicPropertySource
-import org.testcontainers.containers.PostgreSQLContainer
-import org.testcontainers.junit.jupiter.Container
-
-abstract class AbstractTestcontainerTest {
-
- companion object {
- @Container
- val dbContainer = CustomPostgreSQLContainer("postgres:10-alpine")
- .withDatabaseName("test")
- .withUsername("test")
- .withPassword("test") ?: throw RuntimeException("Failed to create testcontainer!")
-
- @DynamicPropertySource
- @JvmStatic
- fun registerDynamicProperties(registry: DynamicPropertyRegistry) {
- registry.add("spring.datasource.url", dbContainer::getJdbcUrl)
- registry.add("spring.datasource.username", dbContainer::getUsername)
- registry.add("spring.datasource.password", dbContainer::getPassword)
- }
- }
-
-}
-
-class CustomPostgreSQLContainer(dockerImageName: String) : PostgreSQLContainer(dockerImageName) {
- override fun stop() {
- // Keep Testcontainer alive until JVM destroys it
- }
-}
\ No newline at end of file
diff --git a/src/test/kotlin/dev/dnpm/etl/processor/EtlProcessorApplicationTests.kt b/src/test/kotlin/dev/dnpm/etl/processor/EtlProcessorApplicationTests.kt
deleted file mode 100644
index 07a201b..0000000
--- a/src/test/kotlin/dev/dnpm/etl/processor/EtlProcessorApplicationTests.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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 .
- */
-
-package dev.dnpm.etl.processor
-
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.extension.ExtendWith
-import org.springframework.boot.test.context.SpringBootTest
-import org.springframework.test.context.junit.jupiter.SpringExtension
-import org.testcontainers.junit.jupiter.Testcontainers
-
-@Testcontainers
-@ExtendWith(SpringExtension::class)
-@SpringBootTest
-class EtlProcessorApplicationTests : AbstractTestcontainerTest() {
-
- @Test
- fun contextLoads() {
- }
-
-}
diff --git a/src/test/kotlin/dev/dnpm/etl/processor/services/RequestServiceIntegrationTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/services/RequestServiceIntegrationTest.kt
deleted file mode 100644
index d71e011..0000000
--- a/src/test/kotlin/dev/dnpm/etl/processor/services/RequestServiceIntegrationTest.kt
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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 .
- */
-
-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
--
cgit v1.2.3
From 422441a3b39806016a952bf7bdff69e0834debca Mon Sep 17 00:00:00 2001
From: Paul-Christian Volkmer
Date: Tue, 8 Aug 2023 16:46:02 +0200
Subject: Add tests for RequestProcessor
---
.../etl/processor/services/RequestProcessorTest.kt | 209 +++++++++++++++++++++
1 file changed, 209 insertions(+)
create mode 100644 src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt
(limited to 'src/test/kotlin')
diff --git a/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt
new file mode 100644
index 0000000..c165cf0
--- /dev/null
+++ b/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt
@@ -0,0 +1,209 @@
+/*
+ * 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 .
+ */
+
+package dev.dnpm.etl.processor.services
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import de.ukw.ccc.bwhc.dto.*
+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.output.RestMtbFileSender
+import dev.dnpm.etl.processor.pseudonym.PseudonymizeService
+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
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import reactor.core.publisher.Sinks
+import java.time.Instant
+import java.util.*
+
+
+@ExtendWith(MockitoExtension::class)
+class RequestProcessorTest {
+
+ private lateinit var pseudonymizeService: PseudonymizeService
+ private lateinit var sender: MtbFileSender
+ private lateinit var requestService: RequestService
+ private lateinit var statisticsUpdateProducer: Sinks.Many
+
+ private lateinit var requestProcessor: RequestProcessor
+
+ @BeforeEach
+ fun setup(
+ @Mock pseudonymizeService: PseudonymizeService,
+ @Mock sender: RestMtbFileSender,
+ @Mock requestService: RequestService,
+ ) {
+ this.pseudonymizeService = pseudonymizeService
+ this.sender = sender
+ this.requestService = requestService
+ this.statisticsUpdateProducer = Sinks.many().multicast().directBestEffort()
+
+ val objectMapper = ObjectMapper()
+
+ requestProcessor = RequestProcessor(
+ pseudonymizeService,
+ listOf(sender),
+ requestService,
+ objectMapper,
+ statisticsUpdateProducer
+ )
+ }
+
+ @Test
+ fun testShouldDetectMtbFileDuplicationAndSaveRequestStatus() {
+ doAnswer {
+ Request(
+ id = 1L,
+ uuid = UUID.randomUUID().toString(),
+ patientId = "TEST_12345678901",
+ pid = "P1",
+ fingerprint = "cwaxsvectyfj4qcw4hiwzx5fwwo7lekyagpzd2ayuf36jlvi6msa",
+ type = RequestType.MTB_FILE,
+ status = RequestStatus.SUCCESS,
+ processedAt = Instant.parse("2023-08-08T02:00:00Z")
+ )
+ }.`when`(requestService).lastMtbFileRequestForPatientPseudonym(anyString())
+
+ doAnswer {
+ false
+ }.`when`(requestService).isLastRequestDeletion(anyString())
+
+ doAnswer {
+ it.arguments[0] as MtbFile
+ }.`when`(pseudonymizeService).pseudonymize(any())
+
+ val mtbFile = MtbFile.builder()
+ .withPatient(
+ Patient.builder()
+ .withId("1")
+ .withBirthDate("2000-08-08")
+ .withGender(Patient.Gender.MALE)
+ .build()
+ )
+ .withConsent(
+ Consent.builder()
+ .withId("1")
+ .withStatus(Consent.Status.ACTIVE)
+ .withPatient("123")
+ .build()
+ )
+ .withEpisode(
+ Episode.builder()
+ .withId("1")
+ .withPatient("1")
+ .withPeriod(PeriodStart("2023-08-08"))
+ .build()
+ )
+ .build()
+
+ this.requestProcessor.processMtbFile(mtbFile)
+
+ val requestCaptor = argumentCaptor()
+ verify(requestService, times(1)).save(requestCaptor.capture())
+ assertThat(requestCaptor.firstValue).isNotNull
+ assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.DUPLICATION)
+ }
+
+ @Test
+ fun testShouldSendMtbFileAndSaveRequestStatus() {
+ doAnswer {
+ Request(
+ id = 1L,
+ uuid = UUID.randomUUID().toString(),
+ patientId = "TEST_12345678901",
+ pid = "P1",
+ fingerprint = "different",
+ type = RequestType.MTB_FILE,
+ status = RequestStatus.SUCCESS,
+ processedAt = Instant.parse("2023-08-08T02:00:00Z")
+ )
+ }.`when`(requestService).lastMtbFileRequestForPatientPseudonym(anyString())
+
+ doAnswer {
+ false
+ }.`when`(requestService).isLastRequestDeletion(anyString())
+
+ doAnswer {
+ MtbFileSender.Response(status = MtbFileSender.ResponseStatus.SUCCESS)
+ }.`when`(sender).send(any())
+
+ doAnswer {
+ it.arguments[0] as MtbFile
+ }.`when`(pseudonymizeService).pseudonymize(any())
+
+ val mtbFile = MtbFile.builder()
+ .withPatient(
+ Patient.builder()
+ .withId("1")
+ .withBirthDate("2000-08-08")
+ .withGender(Patient.Gender.MALE)
+ .build()
+ )
+ .withConsent(
+ Consent.builder()
+ .withId("1")
+ .withStatus(Consent.Status.ACTIVE)
+ .withPatient("123")
+ .build()
+ )
+ .withEpisode(
+ Episode.builder()
+ .withId("1")
+ .withPatient("1")
+ .withPeriod(PeriodStart("2023-08-08"))
+ .build()
+ )
+ .build()
+
+ this.requestProcessor.processMtbFile(mtbFile)
+
+ val requestCaptor = argumentCaptor()
+ verify(requestService, times(1)).save(requestCaptor.capture())
+ assertThat(requestCaptor.firstValue).isNotNull
+ assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.SUCCESS)
+ }
+
+ @Test
+ fun testShouldSendDeleterequestAndSaveRequestStatus() {
+ doAnswer {
+ "PSEUDONYM"
+ }.`when`(pseudonymizeService).patientPseudonym(anyString())
+
+ doAnswer {
+ MtbFileSender.Response(status = MtbFileSender.ResponseStatus.SUCCESS)
+ }.`when`(sender).send(any())
+
+ this.requestProcessor.processDeletion("TEST_12345678901")
+
+ val requestCaptor = argumentCaptor()
+ verify(requestService, times(1)).save(requestCaptor.capture())
+ assertThat(requestCaptor.firstValue).isNotNull
+ assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.SUCCESS)
+ }
+
+}
\ No newline at end of file
--
cgit v1.2.3
From 536ecbbd56d2dad166e995256a6793a675dea167 Mon Sep 17 00:00:00 2001
From: Paul-Christian Volkmer
Date: Tue, 8 Aug 2023 18:52:03 +0200
Subject: Add tests for error response status
---
.../etl/processor/services/RequestProcessorTest.kt | 93 +++++++++++++++++++++-
1 file changed, 91 insertions(+), 2 deletions(-)
(limited to 'src/test/kotlin')
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 c165cf0..12d6e29 100644
--- a/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt
+++ b/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt
@@ -130,7 +130,7 @@ class RequestProcessorTest {
}
@Test
- fun testShouldSendMtbFileAndSaveRequestStatus() {
+ fun testShouldSendMtbFileAndSaveSuccessRequestStatus() {
doAnswer {
Request(
id = 1L,
@@ -189,7 +189,66 @@ class RequestProcessorTest {
}
@Test
- fun testShouldSendDeleterequestAndSaveRequestStatus() {
+ fun testShouldSendMtbFileAndSaveErrorRequestStatus() {
+ doAnswer {
+ Request(
+ id = 1L,
+ uuid = UUID.randomUUID().toString(),
+ patientId = "TEST_12345678901",
+ pid = "P1",
+ fingerprint = "different",
+ type = RequestType.MTB_FILE,
+ status = RequestStatus.SUCCESS,
+ processedAt = Instant.parse("2023-08-08T02:00:00Z")
+ )
+ }.`when`(requestService).lastMtbFileRequestForPatientPseudonym(anyString())
+
+ doAnswer {
+ false
+ }.`when`(requestService).isLastRequestDeletion(anyString())
+
+ doAnswer {
+ MtbFileSender.Response(status = MtbFileSender.ResponseStatus.ERROR)
+ }.`when`(sender).send(any())
+
+ doAnswer {
+ it.arguments[0] as MtbFile
+ }.`when`(pseudonymizeService).pseudonymize(any())
+
+ val mtbFile = MtbFile.builder()
+ .withPatient(
+ Patient.builder()
+ .withId("1")
+ .withBirthDate("2000-08-08")
+ .withGender(Patient.Gender.MALE)
+ .build()
+ )
+ .withConsent(
+ Consent.builder()
+ .withId("1")
+ .withStatus(Consent.Status.ACTIVE)
+ .withPatient("123")
+ .build()
+ )
+ .withEpisode(
+ Episode.builder()
+ .withId("1")
+ .withPatient("1")
+ .withPeriod(PeriodStart("2023-08-08"))
+ .build()
+ )
+ .build()
+
+ this.requestProcessor.processMtbFile(mtbFile)
+
+ val requestCaptor = argumentCaptor()
+ verify(requestService, times(1)).save(requestCaptor.capture())
+ assertThat(requestCaptor.firstValue).isNotNull
+ assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.ERROR)
+ }
+
+ @Test
+ fun testShouldSendDeleteRequestAndSaveSuccessRequestStatus() {
doAnswer {
"PSEUDONYM"
}.`when`(pseudonymizeService).patientPseudonym(anyString())
@@ -206,4 +265,34 @@ class RequestProcessorTest {
assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.SUCCESS)
}
+ @Test
+ fun testShouldSendDeleteRequestAndSaveErrorRequestStatus() {
+ doAnswer {
+ "PSEUDONYM"
+ }.`when`(pseudonymizeService).patientPseudonym(anyString())
+
+ doAnswer {
+ MtbFileSender.Response(status = MtbFileSender.ResponseStatus.ERROR)
+ }.`when`(sender).send(any())
+
+ this.requestProcessor.processDeletion("TEST_12345678901")
+
+ val requestCaptor = argumentCaptor()
+ verify(requestService, times(1)).save(requestCaptor.capture())
+ assertThat(requestCaptor.firstValue).isNotNull
+ assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.ERROR)
+ }
+
+ @Test
+ fun testShouldSendDeleteRequestWithPseudonymErrorAndSaveErrorRequestStatus() {
+ doThrow(RuntimeException()).`when`(pseudonymizeService).patientPseudonym(anyString())
+
+ this.requestProcessor.processDeletion("TEST_12345678901")
+
+ val requestCaptor = argumentCaptor()
+ verify(requestService, times(1)).save(requestCaptor.capture())
+ assertThat(requestCaptor.firstValue).isNotNull
+ assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.ERROR)
+ }
+
}
\ No newline at end of file
--
cgit v1.2.3
From 6ad6ee13a1cae8ed286e80b3a46c458e1052480b Mon Sep 17 00:00:00 2001
From: Paul-Christian Volkmer
Date: Tue, 8 Aug 2023 19:16:59 +0200
Subject: Ignore unknown properties in DataQualityResponse
---
.../etl/processor/services/ReportServiceTest.kt | 70 ++++++++++++++++++++++
1 file changed, 70 insertions(+)
create mode 100644 src/test/kotlin/dev/dnpm/etl/processor/services/ReportServiceTest.kt
(limited to 'src/test/kotlin')
diff --git a/src/test/kotlin/dev/dnpm/etl/processor/services/ReportServiceTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/services/ReportServiceTest.kt
new file mode 100644
index 0000000..70efe2b
--- /dev/null
+++ b/src/test/kotlin/dev/dnpm/etl/processor/services/ReportServiceTest.kt
@@ -0,0 +1,70 @@
+/*
+ * 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 .
+ */
+
+package dev.dnpm.etl.processor.services
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.fasterxml.jackson.module.kotlin.KotlinModule
+import dev.dnpm.etl.processor.monitoring.ReportService
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+
+class ReportServiceTest {
+
+ private lateinit var reportService: ReportService
+
+ @BeforeEach
+ fun setup() {
+ this.reportService = ReportService(ObjectMapper().registerModule(KotlinModule.Builder().build()))
+ }
+
+ @Test
+ fun shouldParseDataQualityReport() {
+ val json = """
+ {
+ "patient": "4711",
+ "issues": [
+ { "severity": "warning", "message": "Warning Message" },
+ { "severity": "error", "message": "Error Message" }
+ ]
+ }
+ """.trimIndent()
+
+ val actual = this.reportService.deserialize(json)
+
+ assertThat(actual).hasSize(2)
+ assertThat(actual[0].severity).isEqualTo(ReportService.Severity.WARNING)
+ assertThat(actual[0].message).isEqualTo("Warning Message")
+ assertThat(actual[1].severity).isEqualTo(ReportService.Severity.ERROR)
+ assertThat(actual[1].message).isEqualTo("Error Message")
+ }
+
+ @Test
+ fun shouldReturnSyntheticDataQualityReportOnParserError() {
+ val invalidResponse = "Invalid Response Data"
+
+ val actual = this.reportService.deserialize(invalidResponse)
+
+ assertThat(actual).hasSize(1)
+ assertThat(actual[0].severity).isEqualTo(ReportService.Severity.ERROR)
+ assertThat(actual[0].message).isEqualTo("Not parsable data quality report '$invalidResponse'")
+ }
+
+}
\ No newline at end of file
--
cgit v1.2.3
From 7739afad1fc82f4ffe0debbebae58874f046d82d Mon Sep 17 00:00:00 2001
From: Paul-Christian Volkmer
Date: Wed, 9 Aug 2023 08:13:27 +0200
Subject: Handle MTB File with rejected consent as deletion request
---
.../etl/processor/web/MtbFileRestControllerTest.kt | 150 +++++++++++++++++++++
1 file changed, 150 insertions(+)
create mode 100644 src/test/kotlin/dev/dnpm/etl/processor/web/MtbFileRestControllerTest.kt
(limited to 'src/test/kotlin')
diff --git a/src/test/kotlin/dev/dnpm/etl/processor/web/MtbFileRestControllerTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/web/MtbFileRestControllerTest.kt
new file mode 100644
index 0000000..2fde35a
--- /dev/null
+++ b/src/test/kotlin/dev/dnpm/etl/processor/web/MtbFileRestControllerTest.kt
@@ -0,0 +1,150 @@
+/*
+ * 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 .
+ */
+
+package dev.dnpm.etl.processor.web
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import de.ukw.ccc.bwhc.dto.*
+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
+import org.mockito.Mock
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.junit.jupiter.MockitoExtension
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.springframework.http.MediaType
+import org.springframework.test.web.servlet.MockMvc
+import org.springframework.test.web.servlet.delete
+import org.springframework.test.web.servlet.post
+import org.springframework.test.web.servlet.setup.MockMvcBuilders
+
+@ExtendWith(MockitoExtension::class)
+class MtbFileRestControllerTest {
+
+ private lateinit var mockMvc: MockMvc
+
+ private lateinit var requestProcessor: RequestProcessor
+
+ private val objectMapper = ObjectMapper()
+
+ @BeforeEach
+ fun setup(
+ @Mock requestProcessor: RequestProcessor
+ ) {
+ this.requestProcessor = requestProcessor
+ val controller = MtbFileRestController(requestProcessor)
+ this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build()
+ }
+
+ @Test
+ fun shouldProcessMtbFilePostRequest() {
+ val mtbFile = MtbFile.builder()
+ .withPatient(
+ Patient.builder()
+ .withId("TEST_12345678")
+ .withBirthDate("2000-08-08")
+ .withGender(Patient.Gender.MALE)
+ .build()
+ )
+ .withConsent(
+ Consent.builder()
+ .withId("1")
+ .withStatus(Consent.Status.ACTIVE)
+ .withPatient("TEST_12345678")
+ .build()
+ )
+ .withEpisode(
+ Episode.builder()
+ .withId("1")
+ .withPatient("TEST_12345678")
+ .withPeriod(PeriodStart("2023-08-08"))
+ .build()
+ )
+ .build()
+
+ mockMvc.post("/mtbfile") {
+ content = objectMapper.writeValueAsString(mtbFile)
+ contentType = MediaType.APPLICATION_JSON
+ }.andExpect {
+ status {
+ isAccepted()
+ }
+ }
+
+ verify(requestProcessor, times(1)).processMtbFile(any())
+ }
+
+ @Test
+ fun shouldProcessMtbFilePostRequestWithRejectedConsent() {
+ val mtbFile = MtbFile.builder()
+ .withPatient(
+ Patient.builder()
+ .withId("TEST_12345678")
+ .withBirthDate("2000-08-08")
+ .withGender(Patient.Gender.MALE)
+ .build()
+ )
+ .withConsent(
+ Consent.builder()
+ .withId("1")
+ .withStatus(Consent.Status.REJECTED)
+ .withPatient("TEST_12345678")
+ .build()
+ )
+ .withEpisode(
+ Episode.builder()
+ .withId("1")
+ .withPatient("TEST_12345678")
+ .withPeriod(PeriodStart("2023-08-08"))
+ .build()
+ )
+ .build()
+
+ mockMvc.post("/mtbfile") {
+ content = objectMapper.writeValueAsString(mtbFile)
+ contentType = MediaType.APPLICATION_JSON
+ }.andExpect {
+ status {
+ isAccepted()
+ }
+ }
+
+ val captor = argumentCaptor()
+ verify(requestProcessor, times(1)).processDeletion(captor.capture())
+ assertThat(captor.firstValue).isEqualTo("TEST_12345678")
+ }
+
+ @Test
+ fun shouldProcessMtbFileDeleteRequest() {
+ mockMvc.delete("/mtbfile/TEST_12345678").andExpect {
+ status {
+ isAccepted()
+ }
+ }
+
+ val captor = argumentCaptor()
+ verify(requestProcessor, times(1)).processDeletion(captor.capture())
+ assertThat(captor.firstValue).isEqualTo("TEST_12345678")
+ }
+
+}
\ No newline at end of file
--
cgit v1.2.3
From 47830ed9f7774c84674e9399cd347d12424f4f42 Mon Sep 17 00:00:00 2001
From: Paul-Christian Volkmer
Date: Wed, 9 Aug 2023 10:34:23 +0200
Subject: Use single MtbFileSender
---
src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src/test/kotlin')
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 12d6e29..6e97343 100644
--- a/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt
+++ b/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt
@@ -67,7 +67,7 @@ class RequestProcessorTest {
requestProcessor = RequestProcessor(
pseudonymizeService,
- listOf(sender),
+ sender,
requestService,
objectMapper,
statisticsUpdateProducer
--
cgit v1.2.3
From 7f048e2483138deecc28208af42546097ef929d7 Mon Sep 17 00:00:00 2001
From: Paul-Christian Volkmer
Date: Wed, 9 Aug 2023 12:26:57 +0200
Subject: Do not append custom prefix to gPAS pseudonym
---
.../processor/pseudonym/PseudonymizeServiceTest.kt | 86 ++++++++++++++++++++++
.../etl/processor/services/RequestProcessorTest.kt | 14 ++--
2 files changed, 93 insertions(+), 7 deletions(-)
create mode 100644 src/test/kotlin/dev/dnpm/etl/processor/pseudonym/PseudonymizeServiceTest.kt
(limited to 'src/test/kotlin')
diff --git a/src/test/kotlin/dev/dnpm/etl/processor/pseudonym/PseudonymizeServiceTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/pseudonym/PseudonymizeServiceTest.kt
new file mode 100644
index 0000000..a30a328
--- /dev/null
+++ b/src/test/kotlin/dev/dnpm/etl/processor/pseudonym/PseudonymizeServiceTest.kt
@@ -0,0 +1,86 @@
+/*
+ * 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 .
+ */
+
+package dev.dnpm.etl.processor.pseudonym
+
+import de.ukw.ccc.bwhc.dto.*
+import dev.dnpm.etl.processor.config.PseudonymizeConfigProperties
+import org.assertj.core.api.Assertions.assertThat
+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.doAnswer
+import org.mockito.kotlin.whenever
+
+@ExtendWith(MockitoExtension::class)
+class PseudonymizeServiceTest {
+
+ private val mtbFile = MtbFile.builder()
+ .withPatient(
+ Patient.builder()
+ .withId("123")
+ .withBirthDate("2000-08-08")
+ .withGender(Patient.Gender.MALE)
+ .build()
+ )
+ .withConsent(
+ Consent.builder()
+ .withId("1")
+ .withStatus(Consent.Status.ACTIVE)
+ .withPatient("123")
+ .build()
+ )
+ .withEpisode(
+ Episode.builder()
+ .withId("1")
+ .withPatient("123")
+ .withPeriod(PeriodStart("2023-08-08"))
+ .build()
+ )
+ .build()
+
+ @Test
+ fun shouldNotUsePseudonymPrefixForGpas(@Mock generator: GpasPseudonymGenerator) {
+ doAnswer {
+ it.arguments[0]
+ }.whenever(generator).generate(anyString())
+
+ val pseudonymizeService = PseudonymizeService(generator, PseudonymizeConfigProperties())
+
+ mtbFile.pseudonymizeWith(pseudonymizeService)
+
+ assertThat(mtbFile.patient.id).isEqualTo("123")
+ }
+
+ @Test
+ fun shouldUsePseudonymPrefixForBuiltin(@Mock generator: AnonymizingGenerator) {
+ doAnswer {
+ it.arguments[0]
+ }.whenever(generator).generate(anyString())
+
+ val pseudonymizeService = PseudonymizeService(generator, PseudonymizeConfigProperties())
+
+ mtbFile.pseudonymizeWith(pseudonymizeService)
+
+ assertThat(mtbFile.patient.id).isEqualTo("UNKNOWN_123")
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt
index 6e97343..8552bbb 100644
--- a/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt
+++ b/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt
@@ -82,7 +82,7 @@ class RequestProcessorTest {
uuid = UUID.randomUUID().toString(),
patientId = "TEST_12345678901",
pid = "P1",
- fingerprint = "cwaxsvectyfj4qcw4hiwzx5fwwo7lekyagpzd2ayuf36jlvi6msa",
+ fingerprint = "xrysxpozhbs2lnrjgf3yq4fzj33kxr7xr5c2cbuskmelfdmckl3a",
type = RequestType.MTB_FILE,
status = RequestStatus.SUCCESS,
processedAt = Instant.parse("2023-08-08T02:00:00Z")
@@ -94,8 +94,8 @@ class RequestProcessorTest {
}.`when`(requestService).isLastRequestDeletion(anyString())
doAnswer {
- it.arguments[0] as MtbFile
- }.`when`(pseudonymizeService).pseudonymize(any())
+ it.arguments[0] as String
+ }.`when`(pseudonymizeService).patientPseudonym(any())
val mtbFile = MtbFile.builder()
.withPatient(
@@ -153,8 +153,8 @@ class RequestProcessorTest {
}.`when`(sender).send(any())
doAnswer {
- it.arguments[0] as MtbFile
- }.`when`(pseudonymizeService).pseudonymize(any())
+ it.arguments[0] as String
+ }.`when`(pseudonymizeService).patientPseudonym(any())
val mtbFile = MtbFile.builder()
.withPatient(
@@ -212,8 +212,8 @@ class RequestProcessorTest {
}.`when`(sender).send(any())
doAnswer {
- it.arguments[0] as MtbFile
- }.`when`(pseudonymizeService).pseudonymize(any())
+ it.arguments[0] as String
+ }.`when`(pseudonymizeService).patientPseudonym(any())
val mtbFile = MtbFile.builder()
.withPatient(
--
cgit v1.2.3
From 1a640ff9dff1cc182c4ffc1d00dff370e42a25de Mon Sep 17 00:00:00 2001
From: Paul-Christian Volkmer
Date: Wed, 9 Aug 2023 18:15:20 +0200
Subject: Decouple request and response processing
---
.../etl/processor/services/RequestProcessorTest.kt | 128 +++++++++++++++----
.../processor/services/ResponseProcessorTest.kt | 142 +++++++++++++++++++++
.../services/kafka/KafkaResponseProcessorTest.kt | 119 +++++++++++++++++
3 files changed, 362 insertions(+), 27 deletions(-)
create mode 100644 src/test/kotlin/dev/dnpm/etl/processor/services/ResponseProcessorTest.kt
create mode 100644 src/test/kotlin/dev/dnpm/etl/processor/services/kafka/KafkaResponseProcessorTest.kt
(limited to 'src/test/kotlin')
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 8552bbb..f9d8182 100644
--- a/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt
+++ b/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt
@@ -37,7 +37,7 @@ import org.mockito.Mockito.*
import org.mockito.junit.jupiter.MockitoExtension
import org.mockito.kotlin.any
import org.mockito.kotlin.argumentCaptor
-import reactor.core.publisher.Sinks
+import org.springframework.context.ApplicationEventPublisher
import java.time.Instant
import java.util.*
@@ -48,7 +48,7 @@ class RequestProcessorTest {
private lateinit var pseudonymizeService: PseudonymizeService
private lateinit var sender: MtbFileSender
private lateinit var requestService: RequestService
- private lateinit var statisticsUpdateProducer: Sinks.Many
+ private lateinit var applicationEventPublisher: ApplicationEventPublisher
private lateinit var requestProcessor: RequestProcessor
@@ -57,11 +57,12 @@ class RequestProcessorTest {
@Mock pseudonymizeService: PseudonymizeService,
@Mock sender: RestMtbFileSender,
@Mock requestService: RequestService,
+ @Mock applicationEventPublisher: ApplicationEventPublisher
) {
this.pseudonymizeService = pseudonymizeService
this.sender = sender
this.requestService = requestService
- this.statisticsUpdateProducer = Sinks.many().multicast().directBestEffort()
+ this.applicationEventPublisher = applicationEventPublisher
val objectMapper = ObjectMapper()
@@ -70,12 +71,12 @@ class RequestProcessorTest {
sender,
requestService,
objectMapper,
- statisticsUpdateProducer
+ applicationEventPublisher
)
}
@Test
- fun testShouldDetectMtbFileDuplicationAndSaveRequestStatus() {
+ fun testShouldSendMtbFileDuplicationAndSaveUnknownRequestStatusAtFirst() {
doAnswer {
Request(
id = 1L,
@@ -126,11 +127,66 @@ class RequestProcessorTest {
val requestCaptor = argumentCaptor()
verify(requestService, times(1)).save(requestCaptor.capture())
assertThat(requestCaptor.firstValue).isNotNull
- assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.DUPLICATION)
+ assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.UNKNOWN)
}
@Test
- fun testShouldSendMtbFileAndSaveSuccessRequestStatus() {
+ fun testShouldDetectMtbFileDuplicationAndSendDuplicationEvent() {
+ doAnswer {
+ Request(
+ id = 1L,
+ uuid = UUID.randomUUID().toString(),
+ patientId = "TEST_12345678901",
+ pid = "P1",
+ fingerprint = "xrysxpozhbs2lnrjgf3yq4fzj33kxr7xr5c2cbuskmelfdmckl3a",
+ type = RequestType.MTB_FILE,
+ status = RequestStatus.SUCCESS,
+ processedAt = Instant.parse("2023-08-08T02:00:00Z")
+ )
+ }.`when`(requestService).lastMtbFileRequestForPatientPseudonym(anyString())
+
+ doAnswer {
+ false
+ }.`when`(requestService).isLastRequestDeletion(anyString())
+
+ doAnswer {
+ it.arguments[0] as String
+ }.`when`(pseudonymizeService).patientPseudonym(any())
+
+ val mtbFile = MtbFile.builder()
+ .withPatient(
+ Patient.builder()
+ .withId("1")
+ .withBirthDate("2000-08-08")
+ .withGender(Patient.Gender.MALE)
+ .build()
+ )
+ .withConsent(
+ Consent.builder()
+ .withId("1")
+ .withStatus(Consent.Status.ACTIVE)
+ .withPatient("123")
+ .build()
+ )
+ .withEpisode(
+ Episode.builder()
+ .withId("1")
+ .withPatient("1")
+ .withPeriod(PeriodStart("2023-08-08"))
+ .build()
+ )
+ .build()
+
+ this.requestProcessor.processMtbFile(mtbFile)
+
+ val eventCaptor = argumentCaptor()
+ verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
+ assertThat(eventCaptor.firstValue).isNotNull
+ assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.DUPLICATION)
+ }
+
+ @Test
+ fun testShouldSendMtbFileAndSendSuccessEvent() {
doAnswer {
Request(
id = 1L,
@@ -149,7 +205,7 @@ class RequestProcessorTest {
}.`when`(requestService).isLastRequestDeletion(anyString())
doAnswer {
- MtbFileSender.Response(status = MtbFileSender.ResponseStatus.SUCCESS)
+ MtbFileSender.Response(status = RequestStatus.SUCCESS)
}.`when`(sender).send(any())
doAnswer {
@@ -182,14 +238,14 @@ class RequestProcessorTest {
this.requestProcessor.processMtbFile(mtbFile)
- val requestCaptor = argumentCaptor()
- verify(requestService, times(1)).save(requestCaptor.capture())
- assertThat(requestCaptor.firstValue).isNotNull
- assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.SUCCESS)
+ val eventCaptor = argumentCaptor()
+ verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
+ assertThat(eventCaptor.firstValue).isNotNull
+ assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.SUCCESS)
}
@Test
- fun testShouldSendMtbFileAndSaveErrorRequestStatus() {
+ fun testShouldSendMtbFileAndSendErrorEvent() {
doAnswer {
Request(
id = 1L,
@@ -208,7 +264,7 @@ class RequestProcessorTest {
}.`when`(requestService).isLastRequestDeletion(anyString())
doAnswer {
- MtbFileSender.Response(status = MtbFileSender.ResponseStatus.ERROR)
+ MtbFileSender.Response(status = RequestStatus.ERROR)
}.`when`(sender).send(any())
doAnswer {
@@ -241,20 +297,20 @@ class RequestProcessorTest {
this.requestProcessor.processMtbFile(mtbFile)
- val requestCaptor = argumentCaptor()
- verify(requestService, times(1)).save(requestCaptor.capture())
- assertThat(requestCaptor.firstValue).isNotNull
- assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.ERROR)
+ val eventCaptor = argumentCaptor()
+ verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
+ assertThat(eventCaptor.firstValue).isNotNull
+ assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.ERROR)
}
@Test
- fun testShouldSendDeleteRequestAndSaveSuccessRequestStatus() {
+ fun testShouldSendDeleteRequestAndSaveUnknownRequestStatusAtFirst() {
doAnswer {
"PSEUDONYM"
}.`when`(pseudonymizeService).patientPseudonym(anyString())
doAnswer {
- MtbFileSender.Response(status = MtbFileSender.ResponseStatus.SUCCESS)
+ MtbFileSender.Response(status = RequestStatus.UNKNOWN)
}.`when`(sender).send(any())
this.requestProcessor.processDeletion("TEST_12345678901")
@@ -262,25 +318,43 @@ class RequestProcessorTest {
val requestCaptor = argumentCaptor()
verify(requestService, times(1)).save(requestCaptor.capture())
assertThat(requestCaptor.firstValue).isNotNull
- assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.SUCCESS)
+ assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.UNKNOWN)
}
@Test
- fun testShouldSendDeleteRequestAndSaveErrorRequestStatus() {
+ fun testShouldSendDeleteRequestAndSendSuccessEvent() {
doAnswer {
"PSEUDONYM"
}.`when`(pseudonymizeService).patientPseudonym(anyString())
doAnswer {
- MtbFileSender.Response(status = MtbFileSender.ResponseStatus.ERROR)
+ MtbFileSender.Response(status = RequestStatus.SUCCESS)
}.`when`(sender).send(any())
this.requestProcessor.processDeletion("TEST_12345678901")
- val requestCaptor = argumentCaptor()
- verify(requestService, times(1)).save(requestCaptor.capture())
- assertThat(requestCaptor.firstValue).isNotNull
- assertThat(requestCaptor.firstValue.status).isEqualTo(RequestStatus.ERROR)
+ val eventCaptor = argumentCaptor()
+ verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
+ assertThat(eventCaptor.firstValue).isNotNull
+ assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.SUCCESS)
+ }
+
+ @Test
+ fun testShouldSendDeleteRequestAndSendErrorEvent() {
+ doAnswer {
+ "PSEUDONYM"
+ }.`when`(pseudonymizeService).patientPseudonym(anyString())
+
+ doAnswer {
+ MtbFileSender.Response(status = RequestStatus.ERROR)
+ }.`when`(sender).send(any())
+
+ this.requestProcessor.processDeletion("TEST_12345678901")
+
+ val eventCaptor = argumentCaptor()
+ verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture())
+ assertThat(eventCaptor.firstValue).isNotNull
+ assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.ERROR)
}
@Test
diff --git a/src/test/kotlin/dev/dnpm/etl/processor/services/ResponseProcessorTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/services/ResponseProcessorTest.kt
new file mode 100644
index 0000000..cfb1111
--- /dev/null
+++ b/src/test/kotlin/dev/dnpm/etl/processor/services/ResponseProcessorTest.kt
@@ -0,0 +1,142 @@
+/*
+ * 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 .
+ */
+
+package dev.dnpm.etl.processor.services
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.fasterxml.jackson.module.kotlin.KotlinModule
+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.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.MethodSource
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.Mock
+import org.mockito.junit.jupiter.MockitoExtension
+import org.mockito.kotlin.*
+import reactor.core.publisher.Sinks
+import java.time.Instant
+import java.util.*
+
+@ExtendWith(MockitoExtension::class)
+class ResponseProcessorTest {
+
+ private lateinit var requestRepository: RequestRepository
+ private lateinit var statisticsUpdateProducer: Sinks.Many
+
+ private lateinit var responseProcessor: ResponseProcessor
+
+ private val testRequest = Request(
+ 1L,
+ "TestID1234",
+ "PSEUDONYM-A",
+ "1",
+ "dummyfingerprint",
+ RequestType.MTB_FILE,
+ RequestStatus.UNKNOWN
+ )
+
+ @BeforeEach
+ fun setup(
+ @Mock requestRepository: RequestRepository,
+ @Mock statisticsUpdateProducer: Sinks.Many
+ ) {
+ val objectMapper = ObjectMapper().registerModule(KotlinModule.Builder().build())
+
+ this.requestRepository = requestRepository
+ this.statisticsUpdateProducer = statisticsUpdateProducer
+
+ this.responseProcessor = ResponseProcessor(requestRepository, statisticsUpdateProducer, objectMapper)
+ }
+
+ @Test
+ fun shouldNotSaveStatusForUnknownRequest() {
+ doAnswer {
+ Optional.empty()
+ }.whenever(requestRepository).findByUuidEquals(anyString())
+
+ val event = ResponseEvent(
+ "TestID1234",
+ Instant.parse("2023-09-09T00:00:00Z"),
+ RequestStatus.SUCCESS
+ )
+
+ this.responseProcessor.handleResponseEvent(event)
+
+ verify(requestRepository, never()).save(any())
+ }
+
+ @Test
+ fun shouldNotSaveStatusWithUnknownState() {
+ doAnswer {
+ Optional.of(testRequest)
+ }.whenever(requestRepository).findByUuidEquals(anyString())
+
+ val event = ResponseEvent(
+ "TestID1234",
+ Instant.parse("2023-09-09T00:00:00Z"),
+ RequestStatus.UNKNOWN
+ )
+
+ this.responseProcessor.handleResponseEvent(event)
+
+ verify(requestRepository, never()).save(any())
+ }
+
+ @ParameterizedTest
+ @MethodSource("requestStatusSource")
+ fun shouldSaveStatusForKnownRequest(requestStatus: RequestStatus) {
+ doAnswer {
+ Optional.of(testRequest)
+ }.whenever(requestRepository).findByUuidEquals(anyString())
+
+ val event = ResponseEvent(
+ "TestID1234",
+ Instant.parse("2023-09-09T00:00:00Z"),
+ requestStatus
+ )
+
+ this.responseProcessor.handleResponseEvent(event)
+
+ val captor = argumentCaptor()
+ verify(requestRepository, times(1)).save(captor.capture())
+ assertThat(captor.firstValue).isNotNull
+ assertThat(captor.firstValue.status).isEqualTo(requestStatus)
+ }
+
+ companion object {
+
+ @JvmStatic
+ fun requestStatusSource(): Set {
+ return setOf(
+ RequestStatus.SUCCESS,
+ RequestStatus.WARNING,
+ RequestStatus.ERROR,
+ RequestStatus.DUPLICATION
+ )
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/kotlin/dev/dnpm/etl/processor/services/kafka/KafkaResponseProcessorTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/services/kafka/KafkaResponseProcessorTest.kt
new file mode 100644
index 0000000..0f524ca
--- /dev/null
+++ b/src/test/kotlin/dev/dnpm/etl/processor/services/kafka/KafkaResponseProcessorTest.kt
@@ -0,0 +1,119 @@
+/*
+ * 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 .
+ */
+
+package dev.dnpm.etl.processor.services.kafka
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.fasterxml.jackson.module.kotlin.KotlinModule
+import dev.dnpm.etl.processor.services.ResponseEvent
+import org.apache.kafka.clients.consumer.ConsumerRecord
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.extension.ExtendWith
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.MethodSource
+import org.mockito.Mock
+import org.mockito.junit.jupiter.MockitoExtension
+import org.mockito.kotlin.any
+import org.mockito.kotlin.never
+import org.mockito.kotlin.times
+import org.mockito.kotlin.verify
+import org.springframework.context.ApplicationEventPublisher
+import org.springframework.http.HttpStatus
+
+@ExtendWith(MockitoExtension::class)
+class KafkaResponseProcessorTest {
+
+ private lateinit var eventPublisher: ApplicationEventPublisher
+ private lateinit var objectMapper: ObjectMapper
+
+ private lateinit var kafkaResponseProcessor: KafkaResponseProcessor
+
+ private fun createkafkaRecord(
+ requestId: String? = null,
+ statusCode: Int = 200,
+ statusBody: Map? = mapOf()
+ ): ConsumerRecord {
+ return ConsumerRecord(
+ "test-topic",
+ 0,
+ 0,
+ if (requestId == null) {
+ null
+ } else {
+ this.objectMapper.writeValueAsString(KafkaResponseProcessor.ResponseKey(requestId))
+ },
+ if (statusBody == null) {
+ ""
+ } else {
+ this.objectMapper.writeValueAsString(KafkaResponseProcessor.ResponseBody(statusCode, statusBody))
+ }
+ )
+ }
+
+ @BeforeEach
+ fun setup(
+ @Mock eventPublisher: ApplicationEventPublisher
+ ) {
+ this.eventPublisher = eventPublisher
+ this.objectMapper = ObjectMapper().registerModule(KotlinModule.Builder().build())
+
+ this.kafkaResponseProcessor = KafkaResponseProcessor(eventPublisher, objectMapper)
+ }
+
+ @Test
+ fun shouldNotProcessRecordsWithoutValidKey() {
+ this.kafkaResponseProcessor.onMessage(createkafkaRecord(null, 200))
+
+ verify(eventPublisher, never()).publishEvent(any())
+ }
+
+ @Test
+ fun shouldNotProcessRecordsWithoutValidBody() {
+ this.kafkaResponseProcessor.onMessage(createkafkaRecord(requestId = "TestID1234", statusBody = null))
+
+ verify(eventPublisher, never()).publishEvent(any())
+ }
+
+ @ParameterizedTest
+ @MethodSource("statusCodeSource")
+ fun shouldProcessValidRecordsWithStatusCode(statusCode: Int) {
+ this.kafkaResponseProcessor.onMessage(createkafkaRecord("TestID1234", statusCode))
+ verify(eventPublisher, times(1)).publishEvent(any())
+ }
+
+ companion object {
+
+ @JvmStatic
+ fun statusCodeSource(): Set {
+ return setOf(
+ HttpStatus.OK,
+ HttpStatus.CREATED,
+ HttpStatus.BAD_REQUEST,
+ HttpStatus.NOT_FOUND,
+ HttpStatus.UNPROCESSABLE_ENTITY,
+ HttpStatus.INTERNAL_SERVER_ERROR
+ )
+ .map { it.value() }
+ .toSet()
+ }
+
+ }
+
+}
\ No newline at end of file
--
cgit v1.2.3
From 2b42a4d262a846feb1f82facbb151be9cabb57b4 Mon Sep 17 00:00:00 2001
From: Paul-Christian Volkmer
Date: Thu, 10 Aug 2023 12:11:39 +0200
Subject: Tests for RestMtbFileSender
---
.../etl/processor/output/RestMtbFileSenderTest.kt | 159 +++++++++++++++++++++
1 file changed, 159 insertions(+)
create mode 100644 src/test/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSenderTest.kt
(limited to 'src/test/kotlin')
diff --git a/src/test/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSenderTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSenderTest.kt
new file mode 100644
index 0000000..17d420a
--- /dev/null
+++ b/src/test/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSenderTest.kt
@@ -0,0 +1,159 @@
+/*
+ * 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 .
+ */
+
+package dev.dnpm.etl.processor.output
+
+import de.ukw.ccc.bwhc.dto.*
+import dev.dnpm.etl.processor.config.RestTargetProperties
+import dev.dnpm.etl.processor.monitoring.RequestStatus
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.MethodSource
+import org.springframework.http.HttpMethod
+import org.springframework.http.HttpStatus
+import org.springframework.test.web.client.MockRestServiceServer
+import org.springframework.test.web.client.match.MockRestRequestMatchers.method
+import org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo
+import org.springframework.test.web.client.response.MockRestResponseCreators.withStatus
+import org.springframework.web.client.RestTemplate
+
+class RestMtbFileSenderTest {
+
+ private lateinit var mockRestServiceServer: MockRestServiceServer
+
+ private lateinit var restMtbFileSender: RestMtbFileSender
+
+ @BeforeEach
+ fun setup() {
+ val restTemplate = RestTemplate()
+ val restTargetProperties = RestTargetProperties("http://localhost:9000/mtbfile")
+
+ this.mockRestServiceServer = MockRestServiceServer.createServer(restTemplate)
+
+ this.restMtbFileSender = RestMtbFileSender(restTemplate, restTargetProperties)
+ }
+
+ @ParameterizedTest
+ @MethodSource("deleteRequestWithResponseSource")
+ fun shouldReturnExpectedResponseForDelete(requestWithResponse: RequestWithResponse) {
+ this.mockRestServiceServer.expect {
+ method(HttpMethod.DELETE)
+ requestTo("/mtbfile")
+ }.andRespond {
+ withStatus(requestWithResponse.httpStatus).body(requestWithResponse.body).createResponse(it)
+ }
+
+ val response = restMtbFileSender.send(MtbFileSender.DeleteRequest("TestID", "PID"))
+ assertThat(response.status).isEqualTo(requestWithResponse.requestStatus)
+ }
+
+ @ParameterizedTest
+ @MethodSource("mtbFileRequestWithResponseSource")
+ fun shouldReturnExpectedResponseForMtbFilePost(requestWithResponse: RequestWithResponse) {
+ this.mockRestServiceServer.expect {
+ method(HttpMethod.POST)
+ requestTo("/mtbfile")
+ }.andRespond {
+ withStatus(requestWithResponse.httpStatus).body(requestWithResponse.body).createResponse(it)
+ }
+
+ val response = restMtbFileSender.send(MtbFileSender.MtbFileRequest("TestID", mtbFile))
+ assertThat(response.status).isEqualTo(requestWithResponse.requestStatus)
+ }
+
+ companion object {
+ data class RequestWithResponse(val httpStatus: HttpStatus, val body: String, val requestStatus: RequestStatus)
+
+ private val warningBody = """
+ {
+ "patient_id": "PID",
+ "issues": [
+ { "severity": "warning", "message": "Something is not right" }
+ ]
+ }
+ """.trimIndent()
+
+ private val errorBody = """
+ {
+ "patient_id": "PID",
+ "issues": [
+ { "severity": "error", "message": "Something is very bad" }
+ ]
+ }
+ """.trimIndent()
+
+ val mtbFile = MtbFile.builder()
+ .withPatient(
+ Patient.builder()
+ .withId("PID")
+ .withBirthDate("2000-08-08")
+ .withGender(Patient.Gender.MALE)
+ .build()
+ )
+ .withConsent(
+ Consent.builder()
+ .withId("1")
+ .withStatus(Consent.Status.ACTIVE)
+ .withPatient("PID")
+ .build()
+ )
+ .withEpisode(
+ Episode.builder()
+ .withId("1")
+ .withPatient("PID")
+ .withPeriod(PeriodStart("2023-08-08"))
+ .build()
+ )
+ .build()
+
+ /**
+ * Synthetic http responses with related request status
+ * Also see: https://ibmi-intra.cs.uni-tuebingen.de/display/ZPM/bwHC+REST+API
+ */
+ @JvmStatic
+ fun mtbFileRequestWithResponseSource(): Set {
+ return setOf(
+ RequestWithResponse(HttpStatus.OK, "{}", RequestStatus.SUCCESS),
+ RequestWithResponse(HttpStatus.CREATED, warningBody, RequestStatus.WARNING),
+ RequestWithResponse(HttpStatus.BAD_REQUEST, "??", RequestStatus.ERROR),
+ RequestWithResponse(HttpStatus.UNPROCESSABLE_ENTITY, errorBody, RequestStatus.ERROR),
+ // Some more errors not mentioned in documentation
+ RequestWithResponse(HttpStatus.NOT_FOUND, "what????", RequestStatus.ERROR),
+ RequestWithResponse(HttpStatus.INTERNAL_SERVER_ERROR, "what????", RequestStatus.ERROR)
+ )
+ }
+
+ /**
+ * Synthetic http responses with related request status
+ * Also see: https://ibmi-intra.cs.uni-tuebingen.de/display/ZPM/bwHC+REST+API
+ */
+ @JvmStatic
+ fun deleteRequestWithResponseSource(): Set {
+ return setOf(
+ RequestWithResponse(HttpStatus.OK, "", RequestStatus.SUCCESS),
+ // Some more errors not mentioned in documentation
+ RequestWithResponse(HttpStatus.NOT_FOUND, "what????", RequestStatus.ERROR),
+ RequestWithResponse(HttpStatus.INTERNAL_SERVER_ERROR, "what????", RequestStatus.ERROR)
+ )
+ }
+ }
+
+
+}
\ No newline at end of file
--
cgit v1.2.3
From 002b0618cf813d48bbff2d287e16f607a4c73d73 Mon Sep 17 00:00:00 2001
From: Paul-Christian Volkmer
Date: Thu, 10 Aug 2023 13:35:35 +0200
Subject: Add tests for KafkaMtbFileSender
---
.../etl/processor/output/KafkaMtbFileSenderTest.kt | 169 +++++++++++++++++++++
1 file changed, 169 insertions(+)
create mode 100644 src/test/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSenderTest.kt
(limited to 'src/test/kotlin')
diff --git a/src/test/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSenderTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSenderTest.kt
new file mode 100644
index 0000000..14bdd5d
--- /dev/null
+++ b/src/test/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSenderTest.kt
@@ -0,0 +1,169 @@
+/*
+ * 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 .
+ */
+
+package dev.dnpm.etl.processor.output
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import de.ukw.ccc.bwhc.dto.*
+import dev.dnpm.etl.processor.config.KafkaTargetProperties
+import dev.dnpm.etl.processor.monitoring.RequestStatus
+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.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.MethodSource
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.Mock
+import org.mockito.junit.jupiter.MockitoExtension
+import org.mockito.kotlin.*
+import org.springframework.kafka.core.KafkaTemplate
+import org.springframework.kafka.support.SendResult
+import java.util.concurrent.CompletableFuture.completedFuture
+import java.util.concurrent.ExecutionException
+
+@ExtendWith(MockitoExtension::class)
+class KafkaMtbFileSenderTest {
+
+ private lateinit var kafkaTemplate: KafkaTemplate
+
+ private lateinit var kafkaMtbFileSender: KafkaMtbFileSender
+
+ private lateinit var objectMapper: ObjectMapper
+
+ @BeforeEach
+ fun setup(
+ @Mock kafkaTemplate: KafkaTemplate
+ ) {
+ val kafkaTargetProperties = KafkaTargetProperties("testtopic")
+ this.objectMapper = ObjectMapper()
+ this.kafkaTemplate = kafkaTemplate
+
+ this.kafkaMtbFileSender = KafkaMtbFileSender(kafkaTemplate, kafkaTargetProperties, objectMapper)
+ }
+
+ @ParameterizedTest
+ @MethodSource("requestWithResponseSource")
+ fun shouldSendMtbFileRequestAndReturnExpectedState(testData: TestData) {
+ doAnswer {
+ if (null != testData.exception) {
+ throw testData.exception
+ }
+ completedFuture(SendResult(null, null))
+ }.whenever(kafkaTemplate).send(anyString(), anyString(), anyString())
+
+ val response = kafkaMtbFileSender.send(MtbFileSender.MtbFileRequest("TestID", mtbFile(Consent.Status.ACTIVE)))
+ assertThat(response.status).isEqualTo(testData.requestStatus)
+ }
+
+ @ParameterizedTest
+ @MethodSource("requestWithResponseSource")
+ fun shouldSendDeleteRequestAndReturnExpectedState(testData: TestData) {
+ doAnswer {
+ if (null != testData.exception) {
+ throw testData.exception
+ }
+ completedFuture(SendResult(null, null))
+ }.whenever(kafkaTemplate).send(anyString(), anyString(), anyString())
+
+ val response = kafkaMtbFileSender.send(MtbFileSender.DeleteRequest("TestID", "PID"))
+ assertThat(response.status).isEqualTo(testData.requestStatus)
+ }
+
+ @Test
+ fun shouldSendMtbFileRequestWithCorrectKeyAndBody() {
+ doAnswer {
+ completedFuture(SendResult(null, null))
+ }.whenever(kafkaTemplate).send(anyString(), anyString(), anyString())
+
+ kafkaMtbFileSender.send(MtbFileSender.MtbFileRequest("TestID", mtbFile(Consent.Status.ACTIVE)))
+
+ val captor = argumentCaptor()
+ verify(kafkaTemplate, times(1)).send(anyString(), captor.capture(), captor.capture())
+ assertThat(captor.firstValue).isNotNull
+ assertThat(captor.firstValue).isEqualTo("{\"pid\": \"PID\", \"eid\": \"1\", \"requestId\": \"TestID\"}")
+ assertThat(captor.secondValue).isNotNull
+ assertThat(captor.secondValue).isEqualTo(objectMapper.writeValueAsString(mtbFile(Consent.Status.ACTIVE)))
+ }
+
+ @Test
+ fun shouldSendDeleteRequestWithCorrectKeyAndBody() {
+ doAnswer {
+ completedFuture(SendResult(null, null))
+ }.whenever(kafkaTemplate).send(anyString(), anyString(), anyString())
+
+ kafkaMtbFileSender.send(MtbFileSender.DeleteRequest("TestID", "PID"))
+
+ val captor = argumentCaptor()
+ verify(kafkaTemplate, times(1)).send(anyString(), captor.capture(), captor.capture())
+ assertThat(captor.firstValue).isNotNull
+ assertThat(captor.firstValue).isEqualTo("{\"pid\": \"PID\", \"requestId\": \"TestID\"}")
+ assertThat(captor.secondValue).isNotNull
+ assertThat(captor.secondValue).isEqualTo(objectMapper.writeValueAsString(mtbFile(Consent.Status.REJECTED)))
+ }
+
+ companion object {
+ fun mtbFile(consentStatus: Consent.Status): MtbFile {
+ return if (consentStatus == Consent.Status.ACTIVE) {
+ MtbFile.builder()
+ .withPatient(
+ Patient.builder()
+ .withId("PID")
+ .withBirthDate("2000-08-08")
+ .withGender(Patient.Gender.MALE)
+ .build()
+ )
+ .withConsent(
+ Consent.builder()
+ .withId("1")
+ .withStatus(consentStatus)
+ .withPatient("PID")
+ .build()
+ )
+ .withEpisode(
+ Episode.builder()
+ .withId("1")
+ .withPatient("PID")
+ .withPeriod(PeriodStart("2023-08-08"))
+ .build()
+ )
+ } else {
+ MtbFile.builder()
+ .withConsent(
+ Consent.builder()
+ .withStatus(consentStatus)
+ .withPatient("PID")
+ .build()
+ )
+ }.build()
+ }
+
+ data class TestData(val requestStatus: RequestStatus, val exception: Throwable? = null)
+
+ @JvmStatic
+ fun requestWithResponseSource(): Set {
+ return setOf(
+ TestData(RequestStatus.UNKNOWN),
+ TestData(RequestStatus.ERROR, InterruptedException("Test interrupted")),
+ TestData(RequestStatus.ERROR, ExecutionException(RuntimeException("Test execution aborted")))
+ )
+ }
+ }
+
+}
\ No newline at end of file
--
cgit v1.2.3
From cb9c5904729c90b86357d0668604b74f4f4e61f7 Mon Sep 17 00:00:00 2001
From: Paul-Christian Volkmer
Date: Fri, 11 Aug 2023 09:13:45 +0200
Subject: Issue #2: Do not serialize JSON string as custom string (#4)
In addition to that, if REST request did not contain a response body, use empty
string as data quality report string.---
.../etl/processor/output/RestMtbFileSenderTest.kt | 60 +++++++++++++++++-----
1 file changed, 48 insertions(+), 12 deletions(-)
(limited to 'src/test/kotlin')
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 17d420a..78b5a45 100644
--- a/src/test/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSenderTest.kt
+++ b/src/test/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSenderTest.kt
@@ -61,7 +61,8 @@ class RestMtbFileSenderTest {
}
val response = restMtbFileSender.send(MtbFileSender.DeleteRequest("TestID", "PID"))
- assertThat(response.status).isEqualTo(requestWithResponse.requestStatus)
+ assertThat(response.status).isEqualTo(requestWithResponse.response.status)
+ assertThat(response.body).isEqualTo(requestWithResponse.response.body)
}
@ParameterizedTest
@@ -75,11 +76,16 @@ class RestMtbFileSenderTest {
}
val response = restMtbFileSender.send(MtbFileSender.MtbFileRequest("TestID", mtbFile))
- assertThat(response.status).isEqualTo(requestWithResponse.requestStatus)
+ assertThat(response.status).isEqualTo(requestWithResponse.response.status)
+ assertThat(response.body).isEqualTo(requestWithResponse.response.body)
}
companion object {
- data class RequestWithResponse(val httpStatus: HttpStatus, val body: String, val requestStatus: RequestStatus)
+ data class RequestWithResponse(
+ val httpStatus: HttpStatus,
+ val body: String,
+ val response: MtbFileSender.Response
+ )
private val warningBody = """
{
@@ -123,6 +129,8 @@ class RestMtbFileSenderTest {
)
.build()
+ private val errorResponseBody = "Sonstiger Fehler bei der Übertragung"
+
/**
* Synthetic http responses with related request status
* Also see: https://ibmi-intra.cs.uni-tuebingen.de/display/ZPM/bwHC+REST+API
@@ -130,13 +138,33 @@ class RestMtbFileSenderTest {
@JvmStatic
fun mtbFileRequestWithResponseSource(): Set {
return setOf(
- RequestWithResponse(HttpStatus.OK, "{}", RequestStatus.SUCCESS),
- RequestWithResponse(HttpStatus.CREATED, warningBody, RequestStatus.WARNING),
- RequestWithResponse(HttpStatus.BAD_REQUEST, "??", RequestStatus.ERROR),
- RequestWithResponse(HttpStatus.UNPROCESSABLE_ENTITY, errorBody, RequestStatus.ERROR),
+ RequestWithResponse(HttpStatus.OK, "{}", MtbFileSender.Response(RequestStatus.SUCCESS, "{}")),
+ RequestWithResponse(
+ HttpStatus.CREATED,
+ warningBody,
+ MtbFileSender.Response(RequestStatus.WARNING, warningBody)
+ ),
+ RequestWithResponse(
+ HttpStatus.BAD_REQUEST,
+ "??",
+ MtbFileSender.Response(RequestStatus.ERROR, errorResponseBody)
+ ),
+ RequestWithResponse(
+ HttpStatus.UNPROCESSABLE_ENTITY,
+ errorBody,
+ MtbFileSender.Response(RequestStatus.ERROR, errorResponseBody)
+ ),
// Some more errors not mentioned in documentation
- RequestWithResponse(HttpStatus.NOT_FOUND, "what????", RequestStatus.ERROR),
- RequestWithResponse(HttpStatus.INTERNAL_SERVER_ERROR, "what????", RequestStatus.ERROR)
+ RequestWithResponse(
+ HttpStatus.NOT_FOUND,
+ "what????",
+ MtbFileSender.Response(RequestStatus.ERROR, errorResponseBody)
+ ),
+ RequestWithResponse(
+ HttpStatus.INTERNAL_SERVER_ERROR,
+ "what????",
+ MtbFileSender.Response(RequestStatus.ERROR, errorResponseBody)
+ )
)
}
@@ -147,10 +175,18 @@ class RestMtbFileSenderTest {
@JvmStatic
fun deleteRequestWithResponseSource(): Set {
return setOf(
- RequestWithResponse(HttpStatus.OK, "", RequestStatus.SUCCESS),
+ RequestWithResponse(HttpStatus.OK, "", MtbFileSender.Response(RequestStatus.SUCCESS)),
// Some more errors not mentioned in documentation
- RequestWithResponse(HttpStatus.NOT_FOUND, "what????", RequestStatus.ERROR),
- RequestWithResponse(HttpStatus.INTERNAL_SERVER_ERROR, "what????", RequestStatus.ERROR)
+ RequestWithResponse(
+ HttpStatus.NOT_FOUND,
+ "what????",
+ MtbFileSender.Response(RequestStatus.ERROR, errorResponseBody)
+ ),
+ RequestWithResponse(
+ HttpStatus.INTERNAL_SERVER_ERROR,
+ "what????",
+ MtbFileSender.Response(RequestStatus.ERROR, errorResponseBody)
+ )
)
}
}
--
cgit v1.2.3
From 6ecb439007b4fa6dec9af1e0334b89fd235a97be Mon Sep 17 00:00:00 2001
From: Paul-Christian Volkmer
Date: Fri, 11 Aug 2023 09:22:54 +0200
Subject: Issue #3: Detect the request type of request with last known status
(#5)
---
.../etl/processor/services/RequestProcessorTest.kt | 8 +--
.../etl/processor/services/RequestServiceTest.kt | 58 +++++++++++++++-------
2 files changed, 43 insertions(+), 23 deletions(-)
(limited to 'src/test/kotlin')
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 f9d8182..7856833 100644
--- a/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt
+++ b/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt
@@ -92,7 +92,7 @@ class RequestProcessorTest {
doAnswer {
false
- }.`when`(requestService).isLastRequestDeletion(anyString())
+ }.`when`(requestService).isLastRequestWithKnownStatusDeletion(anyString())
doAnswer {
it.arguments[0] as String
@@ -147,7 +147,7 @@ class RequestProcessorTest {
doAnswer {
false
- }.`when`(requestService).isLastRequestDeletion(anyString())
+ }.`when`(requestService).isLastRequestWithKnownStatusDeletion(anyString())
doAnswer {
it.arguments[0] as String
@@ -202,7 +202,7 @@ class RequestProcessorTest {
doAnswer {
false
- }.`when`(requestService).isLastRequestDeletion(anyString())
+ }.`when`(requestService).isLastRequestWithKnownStatusDeletion(anyString())
doAnswer {
MtbFileSender.Response(status = RequestStatus.SUCCESS)
@@ -261,7 +261,7 @@ class RequestProcessorTest {
doAnswer {
false
- }.`when`(requestService).isLastRequestDeletion(anyString())
+ }.`when`(requestService).isLastRequestWithKnownStatusDeletion(anyString())
doAnswer {
MtbFileSender.Response(status = RequestStatus.ERROR)
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 3e0a979..3cf8804 100644
--- a/src/test/kotlin/dev/dnpm/etl/processor/services/RequestServiceTest.kt
+++ b/src/test/kotlin/dev/dnpm/etl/processor/services/RequestServiceTest.kt
@@ -68,23 +68,33 @@ class RequestServiceTest {
patientId = "TEST_12345678901",
pid = "P1",
fingerprint = "0123456789abcdef1",
+ type = RequestType.MTB_FILE,
+ status = RequestStatus.WARNING,
+ processedAt = Instant.parse("2023-07-07T00:00:00Z")
+ ),
+ Request(
+ id = 2L,
+ uuid = UUID.randomUUID().toString(),
+ patientId = "TEST_12345678901",
+ pid = "P1",
+ fingerprint = "0123456789abcdefd",
type = RequestType.DELETE,
- status = RequestStatus.SUCCESS,
- processedAt = Instant.parse("2023-08-08T02:00:00Z")
+ status = RequestStatus.WARNING,
+ processedAt = Instant.parse("2023-07-07T02:00:00Z")
),
Request(
- id = 1L,
+ id = 3L,
uuid = UUID.randomUUID().toString(),
- patientId = "TEST_12345678902",
- pid = "P2",
- fingerprint = "0123456789abcdef2",
+ patientId = "TEST_12345678901",
+ pid = "P1",
+ fingerprint = "0123456789abcdef1",
type = RequestType.MTB_FILE,
- status = RequestStatus.WARNING,
- processedAt = Instant.parse("2023-08-08T00:00:00Z")
+ status = RequestStatus.UNKNOWN,
+ processedAt = Instant.parse("2023-08-11T00:00:00Z")
)
)
- val actual = RequestService.isLastRequestDeletion(requests)
+ val actual = RequestService.isLastRequestWithKnownStatusDeletion(requests)
assertThat(actual).isTrue()
}
@@ -98,23 +108,33 @@ class RequestServiceTest {
patientId = "TEST_12345678901",
pid = "P1",
fingerprint = "0123456789abcdef1",
- type = RequestType.DELETE,
- status = RequestStatus.SUCCESS,
- processedAt = Instant.parse("2023-07-07T02:00:00Z")
+ type = RequestType.MTB_FILE,
+ status = RequestStatus.WARNING,
+ processedAt = Instant.parse("2023-07-07T00:00:00Z")
),
Request(
- id = 1L,
+ id = 2L,
uuid = UUID.randomUUID().toString(),
- patientId = "TEST_12345678902",
- pid = "P2",
- fingerprint = "0123456789abcdef2",
+ patientId = "TEST_12345678901",
+ pid = "P1",
+ fingerprint = "0123456789abcdef1",
type = RequestType.MTB_FILE,
status = RequestStatus.WARNING,
- processedAt = Instant.parse("2023-08-08T00:00:00Z")
+ processedAt = Instant.parse("2023-07-07T02:00:00Z")
+ ),
+ Request(
+ id = 3L,
+ uuid = UUID.randomUUID().toString(),
+ patientId = "TEST_12345678901",
+ pid = "P1",
+ fingerprint = "0123456789abcdef1",
+ type = RequestType.MTB_FILE,
+ status = RequestStatus.UNKNOWN,
+ processedAt = Instant.parse("2023-08-11T00:00:00Z")
)
)
- val actual = RequestService.isLastRequestDeletion(requests)
+ val actual = RequestService.isLastRequestWithKnownStatusDeletion(requests)
assertThat(actual).isFalse()
}
@@ -197,7 +217,7 @@ class RequestServiceTest {
@Test
fun isLastRequestDeletionShouldRequestAllRequestsForPatientPseudonym() {
- requestService.isLastRequestDeletion("TEST_12345678901")
+ requestService.isLastRequestWithKnownStatusDeletion("TEST_12345678901")
verify(requestRepository, times(1)).findAllByPatientIdOrderByProcessedAtDesc(anyString())
}
--
cgit v1.2.3
From 72295202ec37a76b90a919e39ae094bb7e56d202 Mon Sep 17 00:00:00 2001
From: Paul-Christian Volkmer
Date: Sat, 12 Aug 2023 22:19:29 +0200
Subject: Code cleanup
---
.../dnpm/etl/processor/output/RestMtbFileSenderTest.kt | 16 ++++++++--------
.../dnpm/etl/processor/services/ResponseProcessorTest.kt | 6 +-----
.../services/kafka/KafkaResponseProcessorTest.kt | 8 ++++----
3 files changed, 13 insertions(+), 17 deletions(-)
(limited to 'src/test/kotlin')
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 78b5a45..0cad285 100644
--- a/src/test/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSenderTest.kt
+++ b/src/test/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSenderTest.kt
@@ -105,7 +105,7 @@ class RestMtbFileSenderTest {
}
""".trimIndent()
- val mtbFile = MtbFile.builder()
+ val mtbFile: MtbFile = MtbFile.builder()
.withPatient(
Patient.builder()
.withId("PID")
@@ -129,7 +129,7 @@ class RestMtbFileSenderTest {
)
.build()
- private val errorResponseBody = "Sonstiger Fehler bei der Übertragung"
+ private const val ERROR_RESPONSE_BODY = "Sonstiger Fehler bei der Übertragung"
/**
* Synthetic http responses with related request status
@@ -147,23 +147,23 @@ class RestMtbFileSenderTest {
RequestWithResponse(
HttpStatus.BAD_REQUEST,
"??",
- MtbFileSender.Response(RequestStatus.ERROR, errorResponseBody)
+ MtbFileSender.Response(RequestStatus.ERROR, ERROR_RESPONSE_BODY)
),
RequestWithResponse(
HttpStatus.UNPROCESSABLE_ENTITY,
errorBody,
- MtbFileSender.Response(RequestStatus.ERROR, errorResponseBody)
+ MtbFileSender.Response(RequestStatus.ERROR, ERROR_RESPONSE_BODY)
),
// Some more errors not mentioned in documentation
RequestWithResponse(
HttpStatus.NOT_FOUND,
"what????",
- MtbFileSender.Response(RequestStatus.ERROR, errorResponseBody)
+ MtbFileSender.Response(RequestStatus.ERROR, ERROR_RESPONSE_BODY)
),
RequestWithResponse(
HttpStatus.INTERNAL_SERVER_ERROR,
"what????",
- MtbFileSender.Response(RequestStatus.ERROR, errorResponseBody)
+ MtbFileSender.Response(RequestStatus.ERROR, ERROR_RESPONSE_BODY)
)
)
}
@@ -180,12 +180,12 @@ class RestMtbFileSenderTest {
RequestWithResponse(
HttpStatus.NOT_FOUND,
"what????",
- MtbFileSender.Response(RequestStatus.ERROR, errorResponseBody)
+ MtbFileSender.Response(RequestStatus.ERROR, ERROR_RESPONSE_BODY)
),
RequestWithResponse(
HttpStatus.INTERNAL_SERVER_ERROR,
"what????",
- MtbFileSender.Response(RequestStatus.ERROR, errorResponseBody)
+ MtbFileSender.Response(RequestStatus.ERROR, ERROR_RESPONSE_BODY)
)
)
}
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 cfb1111..b9e4b7f 100644
--- a/src/test/kotlin/dev/dnpm/etl/processor/services/ResponseProcessorTest.kt
+++ b/src/test/kotlin/dev/dnpm/etl/processor/services/ResponseProcessorTest.kt
@@ -19,8 +19,6 @@
package dev.dnpm.etl.processor.services
-import com.fasterxml.jackson.databind.ObjectMapper
-import com.fasterxml.jackson.module.kotlin.KotlinModule
import dev.dnpm.etl.processor.monitoring.Request
import dev.dnpm.etl.processor.monitoring.RequestRepository
import dev.dnpm.etl.processor.monitoring.RequestStatus
@@ -62,12 +60,10 @@ class ResponseProcessorTest {
@Mock requestRepository: RequestRepository,
@Mock statisticsUpdateProducer: Sinks.Many
) {
- val objectMapper = ObjectMapper().registerModule(KotlinModule.Builder().build())
-
this.requestRepository = requestRepository
this.statisticsUpdateProducer = statisticsUpdateProducer
- this.responseProcessor = ResponseProcessor(requestRepository, statisticsUpdateProducer, objectMapper)
+ this.responseProcessor = ResponseProcessor(requestRepository, statisticsUpdateProducer)
}
@Test
diff --git a/src/test/kotlin/dev/dnpm/etl/processor/services/kafka/KafkaResponseProcessorTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/services/kafka/KafkaResponseProcessorTest.kt
index 0f524ca..6d83146 100644
--- a/src/test/kotlin/dev/dnpm/etl/processor/services/kafka/KafkaResponseProcessorTest.kt
+++ b/src/test/kotlin/dev/dnpm/etl/processor/services/kafka/KafkaResponseProcessorTest.kt
@@ -45,7 +45,7 @@ class KafkaResponseProcessorTest {
private lateinit var kafkaResponseProcessor: KafkaResponseProcessor
- private fun createkafkaRecord(
+ private fun createKafkaRecord(
requestId: String? = null,
statusCode: Int = 200,
statusBody: Map? = mapOf()
@@ -79,14 +79,14 @@ class KafkaResponseProcessorTest {
@Test
fun shouldNotProcessRecordsWithoutValidKey() {
- this.kafkaResponseProcessor.onMessage(createkafkaRecord(null, 200))
+ this.kafkaResponseProcessor.onMessage(createKafkaRecord(null, 200))
verify(eventPublisher, never()).publishEvent(any())
}
@Test
fun shouldNotProcessRecordsWithoutValidBody() {
- this.kafkaResponseProcessor.onMessage(createkafkaRecord(requestId = "TestID1234", statusBody = null))
+ this.kafkaResponseProcessor.onMessage(createKafkaRecord(requestId = "TestID1234", statusBody = null))
verify(eventPublisher, never()).publishEvent(any())
}
@@ -94,7 +94,7 @@ class KafkaResponseProcessorTest {
@ParameterizedTest
@MethodSource("statusCodeSource")
fun shouldProcessValidRecordsWithStatusCode(statusCode: Int) {
- this.kafkaResponseProcessor.onMessage(createkafkaRecord("TestID1234", statusCode))
+ this.kafkaResponseProcessor.onMessage(createKafkaRecord("TestID1234", statusCode))
verify(eventPublisher, times(1)).publishEvent(any())
}
--
cgit v1.2.3
From 8dc82225a4cd45a315fac3efe4d76513e6d536fc Mon Sep 17 00:00:00 2001
From: Paul-Christian Volkmer
Date: Wed, 16 Aug 2023 15:25:46 +0200
Subject: Issue #7: Send and expect requestId in record body, not in record key
(#8)
---
.../etl/processor/output/KafkaMtbFileSenderTest.kt | 12 +++--
.../services/kafka/KafkaResponseProcessorTest.kt | 54 +++++++++++++++++-----
2 files changed, 50 insertions(+), 16 deletions(-)
(limited to 'src/test/kotlin')
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 14bdd5d..3ec9757 100644
--- a/src/test/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSenderTest.kt
+++ b/src/test/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSenderTest.kt
@@ -97,9 +97,9 @@ class KafkaMtbFileSenderTest {
val captor = argumentCaptor()
verify(kafkaTemplate, times(1)).send(anyString(), captor.capture(), captor.capture())
assertThat(captor.firstValue).isNotNull
- assertThat(captor.firstValue).isEqualTo("{\"pid\": \"PID\", \"eid\": \"1\", \"requestId\": \"TestID\"}")
+ assertThat(captor.firstValue).isEqualTo("{\"pid\": \"PID\", \"eid\": \"1\"}")
assertThat(captor.secondValue).isNotNull
- assertThat(captor.secondValue).isEqualTo(objectMapper.writeValueAsString(mtbFile(Consent.Status.ACTIVE)))
+ assertThat(captor.secondValue).isEqualTo(objectMapper.writeValueAsString(kafkaRecordData("TestID", Consent.Status.ACTIVE)))
}
@Test
@@ -113,9 +113,9 @@ class KafkaMtbFileSenderTest {
val captor = argumentCaptor()
verify(kafkaTemplate, times(1)).send(anyString(), captor.capture(), captor.capture())
assertThat(captor.firstValue).isNotNull
- assertThat(captor.firstValue).isEqualTo("{\"pid\": \"PID\", \"requestId\": \"TestID\"}")
+ assertThat(captor.firstValue).isEqualTo("{\"pid\": \"PID\"}")
assertThat(captor.secondValue).isNotNull
- assertThat(captor.secondValue).isEqualTo(objectMapper.writeValueAsString(mtbFile(Consent.Status.REJECTED)))
+ assertThat(captor.secondValue).isEqualTo(objectMapper.writeValueAsString(kafkaRecordData("TestID", Consent.Status.REJECTED)))
}
companion object {
@@ -154,6 +154,10 @@ class KafkaMtbFileSenderTest {
}.build()
}
+ fun kafkaRecordData(requestId: String, consentStatus: Consent.Status): KafkaMtbFileSender.Data {
+ return KafkaMtbFileSender.Data(requestId, mtbFile(consentStatus))
+ }
+
data class TestData(val requestStatus: RequestStatus, val exception: Throwable? = null)
@JvmStatic
diff --git a/src/test/kotlin/dev/dnpm/etl/processor/services/kafka/KafkaResponseProcessorTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/services/kafka/KafkaResponseProcessorTest.kt
index 6d83146..95bf41b 100644
--- a/src/test/kotlin/dev/dnpm/etl/processor/services/kafka/KafkaResponseProcessorTest.kt
+++ b/src/test/kotlin/dev/dnpm/etl/processor/services/kafka/KafkaResponseProcessorTest.kt
@@ -46,7 +46,7 @@ class KafkaResponseProcessorTest {
private lateinit var kafkaResponseProcessor: KafkaResponseProcessor
private fun createKafkaRecord(
- requestId: String? = null,
+ requestId: String,
statusCode: Int = 200,
statusBody: Map? = mapOf()
): ConsumerRecord {
@@ -54,15 +54,11 @@ class KafkaResponseProcessorTest {
"test-topic",
0,
0,
- if (requestId == null) {
- null
- } else {
- this.objectMapper.writeValueAsString(KafkaResponseProcessor.ResponseKey(requestId))
- },
+ null,
if (statusBody == null) {
""
} else {
- this.objectMapper.writeValueAsString(KafkaResponseProcessor.ResponseBody(statusCode, statusBody))
+ this.objectMapper.writeValueAsString(KafkaResponseProcessor.ResponseBody(requestId, statusCode, statusBody))
}
)
}
@@ -78,17 +74,51 @@ class KafkaResponseProcessorTest {
}
@Test
- fun shouldNotProcessRecordsWithoutValidKey() {
- this.kafkaResponseProcessor.onMessage(createKafkaRecord(null, 200))
+ fun shouldNotProcessRecordsWithoutRequestIdInBody() {
+ val record = ConsumerRecord(
+ "test-topic",
+ 0,
+ 0,
+ null,
+ """
+ {
+ "statusCode": 200,
+ "statusBody": {}
+ }
+ """.trimIndent()
+ )
+
+ this.kafkaResponseProcessor.onMessage(record)
+
+ verify(eventPublisher, never()).publishEvent(any())
+ }
+
+ @Test
+ fun shouldProcessRecordsWithAliasNames() {
+ val record = ConsumerRecord(
+ "test-topic",
+ 0,
+ 0,
+ null,
+ """
+ {
+ "request_id": "test0123456789",
+ "status_code": 200,
+ "status_body": {}
+ }
+ """.trimIndent()
+ )
- verify(eventPublisher, never()).publishEvent(any())
+ this.kafkaResponseProcessor.onMessage(record)
+
+ verify(eventPublisher, times(1)).publishEvent(any())
}
@Test
- fun shouldNotProcessRecordsWithoutValidBody() {
+ fun shouldNotProcessRecordsWithoutValidStatusBody() {
this.kafkaResponseProcessor.onMessage(createKafkaRecord(requestId = "TestID1234", statusBody = null))
- verify(eventPublisher, never()).publishEvent(any())
+ verify(eventPublisher, never()).publishEvent(any())
}
@ParameterizedTest
--
cgit v1.2.3