mirror of
https://github.com/pcvolkmer/etl-processor.git
synced 2025-07-01 22:22:53 +00:00
Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
0e1034d964 | |||
6ecb439007 | |||
cb9c590472 |
@ -1,4 +1,4 @@
|
|||||||
# ETL-Processor for bwHC data
|
# ETL-Processor for bwHC data [](https://github.com/CCC-MF/etl-processor/actions/workflows/test.yml)
|
||||||
|
|
||||||
Diese Anwendung versendet ein bwHC-MTB-File an das bwHC-Backend und pseudonymisiert die Patienten-ID.
|
Diese Anwendung versendet ein bwHC-MTB-File an das bwHC-Backend und pseudonymisiert die Patienten-ID.
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "de.ukw.ccc"
|
group = "de.ukw.ccc"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
|
|
||||||
java {
|
java {
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
@ -116,7 +116,7 @@ class RequestServiceIntegrationTest : AbstractTestcontainerTest() {
|
|||||||
fun shouldReturnDeleteRequestAsLastRequest() {
|
fun shouldReturnDeleteRequestAsLastRequest() {
|
||||||
setupTestData()
|
setupTestData()
|
||||||
|
|
||||||
val actual = requestService.isLastRequestDeletion("TEST_12345678901")
|
val actual = requestService.isLastRequestWithKnownStatusDeletion("TEST_12345678901")
|
||||||
|
|
||||||
assertThat(actual).isTrue()
|
assertThat(actual).isTrue()
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ class RestMtbFileSender(
|
|||||||
return MtbFileSender.Response(response.statusCode.asRequestStatus(), "Status-Code: ${response.statusCode.value()}")
|
return MtbFileSender.Response(response.statusCode.asRequestStatus(), "Status-Code: ${response.statusCode.value()}")
|
||||||
}
|
}
|
||||||
logger.debug("Sent file via RestMtbFileSender")
|
logger.debug("Sent file via RestMtbFileSender")
|
||||||
return MtbFileSender.Response(response.statusCode.asRequestStatus())
|
return MtbFileSender.Response(response.statusCode.asRequestStatus(), response.body.orEmpty())
|
||||||
} catch (e: IllegalArgumentException) {
|
} catch (e: IllegalArgumentException) {
|
||||||
logger.error("Not a valid URI to export to: '{}'", restTargetProperties.uri!!)
|
logger.error("Not a valid URI to export to: '{}'", restTargetProperties.uri!!)
|
||||||
} catch (e: RestClientException) {
|
} catch (e: RestClientException) {
|
||||||
|
@ -95,7 +95,7 @@ class RequestProcessor(
|
|||||||
private fun isDuplication(pseudonymizedMtbFile: MtbFile): Boolean {
|
private fun isDuplication(pseudonymizedMtbFile: MtbFile): Boolean {
|
||||||
val lastMtbFileRequestForPatient =
|
val lastMtbFileRequestForPatient =
|
||||||
requestService.lastMtbFileRequestForPatientPseudonym(pseudonymizedMtbFile.patient.id)
|
requestService.lastMtbFileRequestForPatientPseudonym(pseudonymizedMtbFile.patient.id)
|
||||||
val isLastRequestDeletion = requestService.isLastRequestDeletion(pseudonymizedMtbFile.patient.id)
|
val isLastRequestDeletion = requestService.isLastRequestWithKnownStatusDeletion(pseudonymizedMtbFile.patient.id)
|
||||||
|
|
||||||
return null != lastMtbFileRequestForPatient
|
return null != lastMtbFileRequestForPatient
|
||||||
&& !isLastRequestDeletion
|
&& !isLastRequestDeletion
|
||||||
|
@ -38,8 +38,8 @@ class RequestService(
|
|||||||
fun lastMtbFileRequestForPatientPseudonym(patientPseudonym: String) =
|
fun lastMtbFileRequestForPatientPseudonym(patientPseudonym: String) =
|
||||||
Companion.lastMtbFileRequestForPatientPseudonym(allRequestsByPatientPseudonym(patientPseudonym))
|
Companion.lastMtbFileRequestForPatientPseudonym(allRequestsByPatientPseudonym(patientPseudonym))
|
||||||
|
|
||||||
fun isLastRequestDeletion(patientPseudonym: String) =
|
fun isLastRequestWithKnownStatusDeletion(patientPseudonym: String) =
|
||||||
Companion.isLastRequestDeletion(allRequestsByPatientPseudonym(patientPseudonym))
|
Companion.isLastRequestWithKnownStatusDeletion(allRequestsByPatientPseudonym(patientPseudonym))
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@ -48,7 +48,8 @@ class RequestService(
|
|||||||
.sortedByDescending { it.processedAt }
|
.sortedByDescending { it.processedAt }
|
||||||
.firstOrNull { it.status == RequestStatus.SUCCESS || it.status == RequestStatus.WARNING }
|
.firstOrNull { it.status == RequestStatus.SUCCESS || it.status == RequestStatus.WARNING }
|
||||||
|
|
||||||
fun isLastRequestDeletion(allRequests: List<Request>) = allRequests
|
fun isLastRequestWithKnownStatusDeletion(allRequests: List<Request>) = allRequests
|
||||||
|
.filter { it.status != RequestStatus.UNKNOWN }
|
||||||
.maxByOrNull { it.processedAt }?.type == RequestType.DELETE
|
.maxByOrNull { it.processedAt }?.type == RequestType.DELETE
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -55,14 +55,14 @@ class ResponseProcessor(
|
|||||||
RequestStatus.WARNING -> {
|
RequestStatus.WARNING -> {
|
||||||
it.report = Report(
|
it.report = Report(
|
||||||
"Warnungen über mangelhafte Daten",
|
"Warnungen über mangelhafte Daten",
|
||||||
objectMapper.writeValueAsString(event.body)
|
event.body.orElse("")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
RequestStatus.ERROR -> {
|
RequestStatus.ERROR -> {
|
||||||
it.report = Report(
|
it.report = Report(
|
||||||
"Fehler bei der Datenübertragung oder Inhalt nicht verarbeitbar",
|
"Fehler bei der Datenübertragung oder Inhalt nicht verarbeitbar",
|
||||||
objectMapper.writeValueAsString(event.body)
|
event.body.orElse("")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,8 @@ class RestMtbFileSenderTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val response = restMtbFileSender.send(MtbFileSender.DeleteRequest("TestID", "PID"))
|
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
|
@ParameterizedTest
|
||||||
@ -75,11 +76,16 @@ class RestMtbFileSenderTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val response = restMtbFileSender.send(MtbFileSender.MtbFileRequest("TestID", mtbFile))
|
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 {
|
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 = """
|
private val warningBody = """
|
||||||
{
|
{
|
||||||
@ -123,6 +129,8 @@ class RestMtbFileSenderTest {
|
|||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
private val errorResponseBody = "Sonstiger Fehler bei der Übertragung"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Synthetic http responses with related request status
|
* Synthetic http responses with related request status
|
||||||
* Also see: https://ibmi-intra.cs.uni-tuebingen.de/display/ZPM/bwHC+REST+API
|
* Also see: https://ibmi-intra.cs.uni-tuebingen.de/display/ZPM/bwHC+REST+API
|
||||||
@ -130,13 +138,33 @@ class RestMtbFileSenderTest {
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun mtbFileRequestWithResponseSource(): Set<RequestWithResponse> {
|
fun mtbFileRequestWithResponseSource(): Set<RequestWithResponse> {
|
||||||
return setOf(
|
return setOf(
|
||||||
RequestWithResponse(HttpStatus.OK, "{}", RequestStatus.SUCCESS),
|
RequestWithResponse(HttpStatus.OK, "{}", MtbFileSender.Response(RequestStatus.SUCCESS, "{}")),
|
||||||
RequestWithResponse(HttpStatus.CREATED, warningBody, RequestStatus.WARNING),
|
RequestWithResponse(
|
||||||
RequestWithResponse(HttpStatus.BAD_REQUEST, "??", RequestStatus.ERROR),
|
HttpStatus.CREATED,
|
||||||
RequestWithResponse(HttpStatus.UNPROCESSABLE_ENTITY, errorBody, RequestStatus.ERROR),
|
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
|
// Some more errors not mentioned in documentation
|
||||||
RequestWithResponse(HttpStatus.NOT_FOUND, "what????", RequestStatus.ERROR),
|
RequestWithResponse(
|
||||||
RequestWithResponse(HttpStatus.INTERNAL_SERVER_ERROR, "what????", RequestStatus.ERROR)
|
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
|
@JvmStatic
|
||||||
fun deleteRequestWithResponseSource(): Set<RequestWithResponse> {
|
fun deleteRequestWithResponseSource(): Set<RequestWithResponse> {
|
||||||
return setOf(
|
return setOf(
|
||||||
RequestWithResponse(HttpStatus.OK, "", RequestStatus.SUCCESS),
|
RequestWithResponse(HttpStatus.OK, "", MtbFileSender.Response(RequestStatus.SUCCESS)),
|
||||||
// Some more errors not mentioned in documentation
|
// Some more errors not mentioned in documentation
|
||||||
RequestWithResponse(HttpStatus.NOT_FOUND, "what????", RequestStatus.ERROR),
|
RequestWithResponse(
|
||||||
RequestWithResponse(HttpStatus.INTERNAL_SERVER_ERROR, "what????", RequestStatus.ERROR)
|
HttpStatus.NOT_FOUND,
|
||||||
|
"what????",
|
||||||
|
MtbFileSender.Response(RequestStatus.ERROR, errorResponseBody)
|
||||||
|
),
|
||||||
|
RequestWithResponse(
|
||||||
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
|
"what????",
|
||||||
|
MtbFileSender.Response(RequestStatus.ERROR, errorResponseBody)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ class RequestProcessorTest {
|
|||||||
|
|
||||||
doAnswer {
|
doAnswer {
|
||||||
false
|
false
|
||||||
}.`when`(requestService).isLastRequestDeletion(anyString())
|
}.`when`(requestService).isLastRequestWithKnownStatusDeletion(anyString())
|
||||||
|
|
||||||
doAnswer {
|
doAnswer {
|
||||||
it.arguments[0] as String
|
it.arguments[0] as String
|
||||||
@ -147,7 +147,7 @@ class RequestProcessorTest {
|
|||||||
|
|
||||||
doAnswer {
|
doAnswer {
|
||||||
false
|
false
|
||||||
}.`when`(requestService).isLastRequestDeletion(anyString())
|
}.`when`(requestService).isLastRequestWithKnownStatusDeletion(anyString())
|
||||||
|
|
||||||
doAnswer {
|
doAnswer {
|
||||||
it.arguments[0] as String
|
it.arguments[0] as String
|
||||||
@ -202,7 +202,7 @@ class RequestProcessorTest {
|
|||||||
|
|
||||||
doAnswer {
|
doAnswer {
|
||||||
false
|
false
|
||||||
}.`when`(requestService).isLastRequestDeletion(anyString())
|
}.`when`(requestService).isLastRequestWithKnownStatusDeletion(anyString())
|
||||||
|
|
||||||
doAnswer {
|
doAnswer {
|
||||||
MtbFileSender.Response(status = RequestStatus.SUCCESS)
|
MtbFileSender.Response(status = RequestStatus.SUCCESS)
|
||||||
@ -261,7 +261,7 @@ class RequestProcessorTest {
|
|||||||
|
|
||||||
doAnswer {
|
doAnswer {
|
||||||
false
|
false
|
||||||
}.`when`(requestService).isLastRequestDeletion(anyString())
|
}.`when`(requestService).isLastRequestWithKnownStatusDeletion(anyString())
|
||||||
|
|
||||||
doAnswer {
|
doAnswer {
|
||||||
MtbFileSender.Response(status = RequestStatus.ERROR)
|
MtbFileSender.Response(status = RequestStatus.ERROR)
|
||||||
|
@ -68,23 +68,33 @@ class RequestServiceTest {
|
|||||||
patientId = "TEST_12345678901",
|
patientId = "TEST_12345678901",
|
||||||
pid = "P1",
|
pid = "P1",
|
||||||
fingerprint = "0123456789abcdef1",
|
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,
|
type = RequestType.MTB_FILE,
|
||||||
status = RequestStatus.WARNING,
|
status = RequestStatus.WARNING,
|
||||||
processedAt = Instant.parse("2023-08-08T00:00:00Z")
|
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.WARNING,
|
||||||
|
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).isTrue()
|
assertThat(actual).isTrue()
|
||||||
}
|
}
|
||||||
@ -98,23 +108,33 @@ class RequestServiceTest {
|
|||||||
patientId = "TEST_12345678901",
|
patientId = "TEST_12345678901",
|
||||||
pid = "P1",
|
pid = "P1",
|
||||||
fingerprint = "0123456789abcdef1",
|
fingerprint = "0123456789abcdef1",
|
||||||
type = RequestType.DELETE,
|
type = RequestType.MTB_FILE,
|
||||||
status = RequestStatus.SUCCESS,
|
status = RequestStatus.WARNING,
|
||||||
|
processedAt = Instant.parse("2023-07-07T00:00:00Z")
|
||||||
|
),
|
||||||
|
Request(
|
||||||
|
id = 2L,
|
||||||
|
uuid = UUID.randomUUID().toString(),
|
||||||
|
patientId = "TEST_12345678901",
|
||||||
|
pid = "P1",
|
||||||
|
fingerprint = "0123456789abcdef1",
|
||||||
|
type = RequestType.MTB_FILE,
|
||||||
|
status = RequestStatus.WARNING,
|
||||||
processedAt = Instant.parse("2023-07-07T02:00:00Z")
|
processedAt = Instant.parse("2023-07-07T02:00:00Z")
|
||||||
),
|
),
|
||||||
Request(
|
Request(
|
||||||
id = 1L,
|
id = 3L,
|
||||||
uuid = UUID.randomUUID().toString(),
|
uuid = UUID.randomUUID().toString(),
|
||||||
patientId = "TEST_12345678902",
|
patientId = "TEST_12345678901",
|
||||||
pid = "P2",
|
pid = "P1",
|
||||||
fingerprint = "0123456789abcdef2",
|
fingerprint = "0123456789abcdef1",
|
||||||
type = RequestType.MTB_FILE,
|
type = RequestType.MTB_FILE,
|
||||||
status = RequestStatus.WARNING,
|
status = RequestStatus.UNKNOWN,
|
||||||
processedAt = Instant.parse("2023-08-08T00:00:00Z")
|
processedAt = Instant.parse("2023-08-11T00:00:00Z")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val actual = RequestService.isLastRequestDeletion(requests)
|
val actual = RequestService.isLastRequestWithKnownStatusDeletion(requests)
|
||||||
|
|
||||||
assertThat(actual).isFalse()
|
assertThat(actual).isFalse()
|
||||||
}
|
}
|
||||||
@ -197,7 +217,7 @@ class RequestServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun isLastRequestDeletionShouldRequestAllRequestsForPatientPseudonym() {
|
fun isLastRequestDeletionShouldRequestAllRequestsForPatientPseudonym() {
|
||||||
requestService.isLastRequestDeletion("TEST_12345678901")
|
requestService.isLastRequestWithKnownStatusDeletion("TEST_12345678901")
|
||||||
|
|
||||||
verify(requestRepository, times(1)).findAllByPatientIdOrderByProcessedAtDesc(anyString())
|
verify(requestRepository, times(1)).findAllByPatientIdOrderByProcessedAtDesc(anyString())
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user