From befeef31539af73864a2ba21352d62faa5f76af9 Mon Sep 17 00:00:00 2001 From: Paul-Christian Volkmer Date: Thu, 3 Apr 2025 17:06:03 +0200 Subject: [PATCH] feat: use issue severity to create status (#90) --- README.md | 21 ++++ .../processor/config/AppRestConfiguration.kt | 8 +- .../etl/processor/monitoring/ReportService.kt | 11 ++ .../processor/output/RestBwhcMtbFileSender.kt | 6 +- .../processor/output/RestDipMtbFileSender.kt | 6 +- .../etl/processor/output/RestMtbFileSender.kt | 11 +- .../output/RestBwhcMtbFileSenderTest.kt | 106 ++++++++++++----- .../output/RestDipMtbFileSenderTest.kt | 107 +++++++++++++----- .../processor/services/ReportServiceTest.kt | 87 +++++++++++++- 9 files changed, 293 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index 357e44e..5d76a96 100644 --- a/README.md +++ b/README.md @@ -264,6 +264,27 @@ ein Consent-Widerspruch erfolgte. Dieses Vorgehen empfiehlt sich, wenn Sie gespeicherte Records nachgelagert für andere Auswertungen verwenden möchten. +### Antworten und Statusauswertung + +Anfragen and bwHC-Backend aus Versionen bis 0.9.x wurden wie folgt behandelt: + +| HTTP-Response | Status | +|----------------|-----------| +| `HTTP 200` | `SUCCESS` | +| `HTTP 201` | `WARNING` | +| `HTTP 400-...` | `ERROR` | + +Dies konnte dazu führen, dass zwar mit einem `HTTP 201` geantwortet wurde, aber dennoch in der Issue-Liste die +Severity `error` aufgetaucht ist. + +Ab Version 0.10 wird die Issue-Liste der Antwort verwendet und die darion enthaltene höchste Severity-Stufe als Ergebnis verwendet. + +| Höchste Severity | Status | +|------------------|-----------| +| `info` | `SUCCESS` | +| `warning` | `WARNING` | +| `error`, `fatal` | `ERROR` | + ## Docker-Images Diese Anwendung ist auch als Docker-Image verfügbar: https://github.com/pcvolkmer/etl-processor/pkgs/container/etl-processor diff --git a/src/main/kotlin/dev/dnpm/etl/processor/config/AppRestConfiguration.kt b/src/main/kotlin/dev/dnpm/etl/processor/config/AppRestConfiguration.kt index a393267..1a18924 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/config/AppRestConfiguration.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/config/AppRestConfiguration.kt @@ -21,6 +21,7 @@ package dev.dnpm.etl.processor.config import dev.dnpm.etl.processor.monitoring.ConnectionCheckResult import dev.dnpm.etl.processor.monitoring.ConnectionCheckService +import dev.dnpm.etl.processor.monitoring.ReportService import dev.dnpm.etl.processor.monitoring.RestConnectionCheckService import dev.dnpm.etl.processor.output.MtbFileSender import dev.dnpm.etl.processor.output.RestBwhcMtbFileSender @@ -53,15 +54,16 @@ class AppRestConfiguration { fun restMtbFileSender( restTemplate: RestTemplate, restTargetProperties: RestTargetProperties, - retryTemplate: RetryTemplate + retryTemplate: RetryTemplate, + reportService: ReportService, ): MtbFileSender { if (restTargetProperties.isBwhc) { logger.info("Selected 'RestBwhcMtbFileSender'") - return RestBwhcMtbFileSender(restTemplate, restTargetProperties, retryTemplate) + return RestBwhcMtbFileSender(restTemplate, restTargetProperties, retryTemplate, reportService) } logger.info("Selected 'RestDipMtbFileSender'") - return RestDipMtbFileSender(restTemplate, restTargetProperties, retryTemplate) + return RestDipMtbFileSender(restTemplate, restTargetProperties, retryTemplate, reportService) } @Bean diff --git a/src/main/kotlin/dev/dnpm/etl/processor/monitoring/ReportService.kt b/src/main/kotlin/dev/dnpm/etl/processor/monitoring/ReportService.kt index 062f749..9f4c568 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/monitoring/ReportService.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/monitoring/ReportService.kt @@ -25,6 +25,8 @@ import com.fasterxml.jackson.annotation.JsonValue import com.fasterxml.jackson.core.JsonParseException import com.fasterxml.jackson.databind.JsonMappingException import com.fasterxml.jackson.databind.ObjectMapper +import dev.dnpm.etl.processor.monitoring.ReportService.Issue +import dev.dnpm.etl.processor.monitoring.ReportService.Severity class ReportService( private val objectMapper: ObjectMapper @@ -63,4 +65,13 @@ class ReportService( WARNING("warning"), INFO("info") } +} + +fun List.asRequestStatus(): RequestStatus { + val severity = this.minOfOrNull { it.severity } + return when (severity) { + Severity.FATAL, Severity.ERROR -> RequestStatus.ERROR + Severity.WARNING -> RequestStatus.WARNING + else -> RequestStatus.SUCCESS + } } \ No newline at end of file diff --git a/src/main/kotlin/dev/dnpm/etl/processor/output/RestBwhcMtbFileSender.kt b/src/main/kotlin/dev/dnpm/etl/processor/output/RestBwhcMtbFileSender.kt index f4a58e8..fbe6d0d 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/output/RestBwhcMtbFileSender.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/output/RestBwhcMtbFileSender.kt @@ -21,6 +21,7 @@ package dev.dnpm.etl.processor.output import dev.dnpm.etl.processor.PatientPseudonym import dev.dnpm.etl.processor.config.RestTargetProperties +import dev.dnpm.etl.processor.monitoring.ReportService import org.springframework.retry.support.RetryTemplate import org.springframework.web.client.RestTemplate import org.springframework.web.util.UriComponentsBuilder @@ -28,8 +29,9 @@ import org.springframework.web.util.UriComponentsBuilder class RestBwhcMtbFileSender( restTemplate: RestTemplate, private val restTargetProperties: RestTargetProperties, - retryTemplate: RetryTemplate -) : RestMtbFileSender(restTemplate, restTargetProperties, retryTemplate) { + retryTemplate: RetryTemplate, + reportService: ReportService, +) : RestMtbFileSender(restTemplate, restTargetProperties, retryTemplate, reportService) { override fun sendUrl(): String { return UriComponentsBuilder diff --git a/src/main/kotlin/dev/dnpm/etl/processor/output/RestDipMtbFileSender.kt b/src/main/kotlin/dev/dnpm/etl/processor/output/RestDipMtbFileSender.kt index 42dbb30..1e6a5a7 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/output/RestDipMtbFileSender.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/output/RestDipMtbFileSender.kt @@ -21,6 +21,7 @@ package dev.dnpm.etl.processor.output import dev.dnpm.etl.processor.PatientPseudonym import dev.dnpm.etl.processor.config.RestTargetProperties +import dev.dnpm.etl.processor.monitoring.ReportService import org.springframework.retry.support.RetryTemplate import org.springframework.web.client.RestTemplate import org.springframework.web.util.UriComponentsBuilder @@ -28,8 +29,9 @@ import org.springframework.web.util.UriComponentsBuilder class RestDipMtbFileSender( restTemplate: RestTemplate, private val restTargetProperties: RestTargetProperties, - retryTemplate: RetryTemplate -) : RestMtbFileSender(restTemplate, restTargetProperties, retryTemplate) { + retryTemplate: RetryTemplate, + reportService: ReportService +) : RestMtbFileSender(restTemplate, restTargetProperties, retryTemplate, reportService) { override fun sendUrl(): String { return UriComponentsBuilder diff --git a/src/main/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSender.kt b/src/main/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSender.kt index 016981c..90e3629 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSender.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSender.kt @@ -22,6 +22,8 @@ package dev.dnpm.etl.processor.output import dev.dnpm.etl.processor.config.RestTargetProperties import dev.dnpm.etl.processor.monitoring.RequestStatus import dev.dnpm.etl.processor.PatientPseudonym +import dev.dnpm.etl.processor.monitoring.ReportService +import dev.dnpm.etl.processor.monitoring.asRequestStatus import org.slf4j.LoggerFactory import org.springframework.http.HttpEntity import org.springframework.http.HttpHeaders @@ -34,7 +36,8 @@ import org.springframework.web.client.RestTemplate abstract class RestMtbFileSender( private val restTemplate: RestTemplate, private val restTargetProperties: RestTargetProperties, - private val retryTemplate: RetryTemplate + private val retryTemplate: RetryTemplate, + private val reportService: ReportService ) : MtbFileSender { private val logger = LoggerFactory.getLogger(RestMtbFileSender::class.java) @@ -56,19 +59,19 @@ abstract class RestMtbFileSender( if (!response.statusCode.is2xxSuccessful) { logger.warn("Error sending to remote system: {}", response.body) return@execute MtbFileSender.Response( - response.statusCode.asRequestStatus(), + reportService.deserialize(response.body).asRequestStatus(), "Status-Code: ${response.statusCode.value()}" ) } logger.debug("Sent file via RestMtbFileSender") - return@execute MtbFileSender.Response(response.statusCode.asRequestStatus(), response.body.orEmpty()) + return@execute MtbFileSender.Response(reportService.deserialize(response.body).asRequestStatus(), response.body.orEmpty()) } } catch (e: IllegalArgumentException) { logger.error("Not a valid URI to export to: '{}'", restTargetProperties.uri!!) } catch (e: RestClientResponseException) { logger.info(restTargetProperties.uri!!.toString()) logger.error("Request data not accepted by remote system", e) - return MtbFileSender.Response(e.statusCode.asRequestStatus(), e.responseBodyAsString) + return MtbFileSender.Response(reportService.deserialize(e.responseBodyAsString).asRequestStatus(), e.responseBodyAsString) } return MtbFileSender.Response(RequestStatus.ERROR, "Sonstiger Fehler bei der Übertragung") } diff --git a/src/test/kotlin/dev/dnpm/etl/processor/output/RestBwhcMtbFileSenderTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/output/RestBwhcMtbFileSenderTest.kt index 5063a97..ffbc65c 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/output/RestBwhcMtbFileSenderTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/output/RestBwhcMtbFileSenderTest.kt @@ -19,14 +19,18 @@ package dev.dnpm.etl.processor.output +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.KotlinModule import de.ukw.ccc.bwhc.dto.* import dev.dnpm.etl.processor.PatientPseudonym import dev.dnpm.etl.processor.RequestId import dev.dnpm.etl.processor.config.RestTargetProperties +import dev.dnpm.etl.processor.monitoring.ReportService 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.Arguments import org.junit.jupiter.params.provider.MethodSource import org.springframework.http.HttpMethod import org.springframework.http.HttpStatus @@ -45,6 +49,8 @@ class RestBwhcMtbFileSenderTest { private lateinit var restMtbFileSender: RestMtbFileSender + private var reportService = ReportService(ObjectMapper().registerModule(KotlinModule.Builder().build())) + @BeforeEach fun setup() { val restTemplate = RestTemplate() @@ -53,7 +59,8 @@ class RestBwhcMtbFileSenderTest { this.mockRestServiceServer = MockRestServiceServer.createServer(restTemplate) - this.restMtbFileSender = RestBwhcMtbFileSender(restTemplate, restTargetProperties, retryTemplate) + this.restMtbFileSender = + RestBwhcMtbFileSender(restTemplate, restTargetProperties, retryTemplate, reportService) } @ParameterizedTest @@ -94,7 +101,8 @@ class RestBwhcMtbFileSenderTest { val retryTemplate = RetryTemplateBuilder().customPolicy(SimpleRetryPolicy(3)).build() this.mockRestServiceServer = MockRestServiceServer.createServer(restTemplate) - this.restMtbFileSender = RestBwhcMtbFileSender(restTemplate, restTargetProperties, retryTemplate) + this.restMtbFileSender = + RestBwhcMtbFileSender(restTemplate, restTargetProperties, retryTemplate, reportService) val expectedCount = when (requestWithResponse.httpStatus) { // OK - No Retry @@ -123,7 +131,8 @@ class RestBwhcMtbFileSenderTest { val retryTemplate = RetryTemplateBuilder().customPolicy(SimpleRetryPolicy(3)).build() this.mockRestServiceServer = MockRestServiceServer.createServer(restTemplate) - this.restMtbFileSender = RestBwhcMtbFileSender(restTemplate, restTargetProperties, retryTemplate) + this.restMtbFileSender = + RestBwhcMtbFileSender(restTemplate, restTargetProperties, retryTemplate, reportService) val expectedCount = when (requestWithResponse.httpStatus) { // OK - No Retry @@ -154,24 +163,6 @@ class RestBwhcMtbFileSenderTest { val TEST_REQUEST_ID = RequestId("TestId") val TEST_PATIENT_PSEUDONYM = PatientPseudonym("PID") - 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 = MtbFile.builder() .withPatient( Patient.builder() @@ -205,21 +196,34 @@ class RestBwhcMtbFileSenderTest { @JvmStatic fun mtbFileRequestWithResponseSource(): Set { return setOf( - RequestWithResponse(HttpStatus.OK, "{}", MtbFileSender.Response(RequestStatus.SUCCESS, "{}")), + RequestWithResponse( + HttpStatus.OK, + responseBodyWithMaxSeverity(ReportService.Severity.INFO), + MtbFileSender.Response( + RequestStatus.SUCCESS, + responseBodyWithMaxSeverity(ReportService.Severity.INFO) + ) + ), RequestWithResponse( HttpStatus.CREATED, - warningBody, - MtbFileSender.Response(RequestStatus.WARNING, warningBody) + responseBodyWithMaxSeverity(ReportService.Severity.WARNING), + MtbFileSender.Response( + RequestStatus.WARNING, + responseBodyWithMaxSeverity(ReportService.Severity.WARNING) + ) ), RequestWithResponse( HttpStatus.BAD_REQUEST, - ERROR_RESPONSE_BODY, - MtbFileSender.Response(RequestStatus.ERROR, ERROR_RESPONSE_BODY) + responseBodyWithMaxSeverity(ReportService.Severity.ERROR), + MtbFileSender.Response(RequestStatus.ERROR, responseBodyWithMaxSeverity(ReportService.Severity.ERROR)) ), RequestWithResponse( HttpStatus.UNPROCESSABLE_ENTITY, - errorBody, - MtbFileSender.Response(RequestStatus.ERROR, errorBody) + responseBodyWithMaxSeverity(ReportService.Severity.FATAL), + MtbFileSender.Response( + RequestStatus.ERROR, + responseBodyWithMaxSeverity(ReportService.Severity.FATAL) + ) ), // Some more errors not mentioned in documentation RequestWithResponse( @@ -256,6 +260,52 @@ class RestBwhcMtbFileSenderTest { ) ) } + + fun responseBodyWithMaxSeverity(severity: ReportService.Severity): String { + return when (severity) { + ReportService.Severity.INFO -> """ + { + "patient": "PID", + "issues": [ + { "severity": "info", "message": "Info Message" } + ] + } + """ + + ReportService.Severity.WARNING -> """ + { + "patient": "PID", + "issues": [ + { "severity": "info", "message": "Info Message" }, + { "severity": "warning", "message": "Warning Message" } + ] + } + """ + + ReportService.Severity.ERROR -> """ + { + "patient": "PID", + "issues": [ + { "severity": "info", "message": "Info Message" }, + { "severity": "warning", "message": "Warning Message" }, + { "severity": "error", "message": "Error Message" } + ] + } + """ + + ReportService.Severity.FATAL -> """ + { + "patient": "PID", + "issues": [ + { "severity": "info", "message": "Info Message" }, + { "severity": "warning", "message": "Warning Message" }, + { "severity": "error", "message": "Error Message" }, + { "severity": "fatal", "message": "Fatal Message" } + ] + } + """ + } + } } diff --git a/src/test/kotlin/dev/dnpm/etl/processor/output/RestDipMtbFileSenderTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/output/RestDipMtbFileSenderTest.kt index 26e25c6..005c0fd 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/output/RestDipMtbFileSenderTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/output/RestDipMtbFileSenderTest.kt @@ -19,13 +19,17 @@ package dev.dnpm.etl.processor.output +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.KotlinModule import de.ukw.ccc.bwhc.dto.* import dev.dnpm.etl.processor.PatientPseudonym import dev.dnpm.etl.processor.RequestId import dev.dnpm.etl.processor.config.AppConfigProperties import dev.dnpm.etl.processor.config.AppConfiguration import dev.dnpm.etl.processor.config.RestTargetProperties +import dev.dnpm.etl.processor.monitoring.ReportService import dev.dnpm.etl.processor.monitoring.RequestStatus +import dev.dnpm.etl.processor.output.RestBwhcMtbFileSenderTest.Companion import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.params.ParameterizedTest @@ -48,6 +52,8 @@ class RestDipMtbFileSenderTest { private lateinit var restMtbFileSender: RestMtbFileSender + private var reportService = ReportService(ObjectMapper().registerModule(KotlinModule.Builder().build())) + @BeforeEach fun setup() { val restTemplate = RestTemplate() @@ -56,7 +62,7 @@ class RestDipMtbFileSenderTest { this.mockRestServiceServer = MockRestServiceServer.createServer(restTemplate) - this.restMtbFileSender = RestDipMtbFileSender(restTemplate, restTargetProperties, retryTemplate) + this.restMtbFileSender = RestDipMtbFileSender(restTemplate, restTargetProperties, retryTemplate, reportService) } @ParameterizedTest @@ -98,11 +104,14 @@ class RestDipMtbFileSenderTest { retryTemplate.setBackOffPolicy(NoBackOffPolicy()) this.mockRestServiceServer = MockRestServiceServer.createServer(restTemplate) - this.restMtbFileSender = RestDipMtbFileSender(restTemplate, restTargetProperties, retryTemplate) + this.restMtbFileSender = + RestDipMtbFileSender(restTemplate, restTargetProperties, retryTemplate, reportService) val expectedCount = when (requestWithResponse.httpStatus) { // OK - No Retry - HttpStatus.OK, HttpStatus.CREATED, HttpStatus.UNPROCESSABLE_ENTITY, HttpStatus.BAD_REQUEST -> ExpectedCount.max(1) + HttpStatus.OK, HttpStatus.CREATED, HttpStatus.UNPROCESSABLE_ENTITY, HttpStatus.BAD_REQUEST -> ExpectedCount.max( + 1 + ) // Request failed - Retry max 3 times else -> ExpectedCount.max(3) } @@ -128,11 +137,14 @@ class RestDipMtbFileSenderTest { retryTemplate.setBackOffPolicy(NoBackOffPolicy()) this.mockRestServiceServer = MockRestServiceServer.createServer(restTemplate) - this.restMtbFileSender = RestDipMtbFileSender(restTemplate, restTargetProperties, retryTemplate) + this.restMtbFileSender = + RestDipMtbFileSender(restTemplate, restTargetProperties, retryTemplate, reportService) val expectedCount = when (requestWithResponse.httpStatus) { // OK - No Retry - HttpStatus.OK, HttpStatus.CREATED, HttpStatus.UNPROCESSABLE_ENTITY, HttpStatus.BAD_REQUEST -> ExpectedCount.max(1) + HttpStatus.OK, HttpStatus.CREATED, HttpStatus.UNPROCESSABLE_ENTITY, HttpStatus.BAD_REQUEST -> ExpectedCount.max( + 1 + ) // Request failed - Retry max 3 times else -> ExpectedCount.max(3) } @@ -159,24 +171,6 @@ class RestDipMtbFileSenderTest { val TEST_REQUEST_ID = RequestId("TestId") val TEST_PATIENT_PSEUDONYM = PatientPseudonym("PID") - 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 = MtbFile.builder() .withPatient( Patient.builder() @@ -210,21 +204,28 @@ class RestDipMtbFileSenderTest { @JvmStatic fun mtbFileRequestWithResponseSource(): Set { return setOf( - RequestWithResponse(HttpStatus.OK, "{}", MtbFileSender.Response(RequestStatus.SUCCESS, "{}")), + RequestWithResponse( + HttpStatus.OK, + responseBodyWithMaxSeverity(ReportService.Severity.INFO), + MtbFileSender.Response( + RequestStatus.SUCCESS, + responseBodyWithMaxSeverity(ReportService.Severity.INFO) + ) + ), RequestWithResponse( HttpStatus.CREATED, - warningBody, - MtbFileSender.Response(RequestStatus.WARNING, warningBody) + responseBodyWithMaxSeverity(ReportService.Severity.WARNING), + MtbFileSender.Response(RequestStatus.WARNING, responseBodyWithMaxSeverity(ReportService.Severity.WARNING)) ), RequestWithResponse( HttpStatus.BAD_REQUEST, - ERROR_RESPONSE_BODY, - MtbFileSender.Response(RequestStatus.ERROR, ERROR_RESPONSE_BODY) + responseBodyWithMaxSeverity(ReportService.Severity.ERROR), + MtbFileSender.Response(RequestStatus.ERROR, responseBodyWithMaxSeverity(ReportService.Severity.ERROR)) ), RequestWithResponse( HttpStatus.UNPROCESSABLE_ENTITY, - errorBody, - MtbFileSender.Response(RequestStatus.ERROR, errorBody) + responseBodyWithMaxSeverity(ReportService.Severity.ERROR), + MtbFileSender.Response(RequestStatus.ERROR, responseBodyWithMaxSeverity(ReportService.Severity.ERROR)) ), // Some more errors not mentioned in documentation RequestWithResponse( @@ -261,6 +262,52 @@ class RestDipMtbFileSenderTest { ) ) } + + fun responseBodyWithMaxSeverity(severity: ReportService.Severity): String { + return when (severity) { + ReportService.Severity.INFO -> """ + { + "patient": "PID", + "issues": [ + { "severity": "info", "message": "Info Message" } + ] + } + """ + + ReportService.Severity.WARNING -> """ + { + "patient": "PID", + "issues": [ + { "severity": "info", "message": "Info Message" }, + { "severity": "warning", "message": "Warning Message" } + ] + } + """ + + ReportService.Severity.ERROR -> """ + { + "patient": "PID", + "issues": [ + { "severity": "info", "message": "Info Message" }, + { "severity": "warning", "message": "Warning Message" }, + { "severity": "error", "message": "Error Message" } + ] + } + """ + + ReportService.Severity.FATAL -> """ + { + "patient": "PID", + "issues": [ + { "severity": "info", "message": "Info Message" }, + { "severity": "warning", "message": "Warning Message" }, + { "severity": "error", "message": "Error Message" }, + { "severity": "fatal", "message": "Fatal Message" } + ] + } + """ + } + } } diff --git a/src/test/kotlin/dev/dnpm/etl/processor/services/ReportServiceTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/services/ReportServiceTest.kt index 349202a..fc95808 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/services/ReportServiceTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/services/ReportServiceTest.kt @@ -1,7 +1,7 @@ /* * This file is part of ETL-Processor * - * Copyright (c) 2023 Comprehensive Cancer Center Mainfranken, Datenintegrationszentrum Philipps-Universität Marburg and Contributors + * Copyright (c) 2025 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 @@ -22,9 +22,14 @@ 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 dev.dnpm.etl.processor.monitoring.RequestStatus +import dev.dnpm.etl.processor.monitoring.asRequestStatus import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource class ReportServiceTest { @@ -60,6 +65,15 @@ class ReportServiceTest { assertThat(actual[2].message).isEqualTo("Warning Message") assertThat(actual[3].severity).isEqualTo(ReportService.Severity.INFO) assertThat(actual[3].message).isEqualTo("Info Message") + + assertThat(actual.asRequestStatus()).isEqualTo(RequestStatus.ERROR) + } + + @ParameterizedTest + @MethodSource("testData") + fun shouldParseDataQualityReport(json: String, requestStatus: RequestStatus) { + val actual = this.reportService.deserialize(json) + assertThat(actual.asRequestStatus()).isEqualTo(requestStatus) } @Test @@ -73,4 +87,75 @@ class ReportServiceTest { assertThat(actual[0].message).isEqualTo("Not parsable data quality report '$invalidResponse'") } + companion object { + + @JvmStatic + fun testData(): Set { + return setOf( + Arguments.of( + """ + { + "patient": "4711", + "issues": [ + { "severity": "info", "message": "Info Message" }, + { "severity": "warning", "message": "Warning Message" }, + { "severity": "error", "message": "Error Message" }, + { "severity": "fatal", "message": "Fatal Message" } + ] + } + """.trimIndent(), + RequestStatus.ERROR + ), + Arguments.of( + """ + { + "patient": "4711", + "issues": [ + { "severity": "info", "message": "Info Message" }, + { "severity": "warning", "message": "Warning Message" }, + { "severity": "error", "message": "Error Message" } + ] + } + """.trimIndent(), + RequestStatus.ERROR + ), + Arguments.of( + """ + { + "patient": "4711", + "issues": [ + { "severity": "error", "message": "Error Message" } + { "severity": "info", "message": "Info Message" } + ] + } + """.trimIndent(), + RequestStatus.ERROR + ), + Arguments.of( + """ + { + "patient": "4711", + "issues": [ + { "severity": "info", "message": "Info Message" }, + { "severity": "warning", "message": "Warning Message" } + ] + } + """.trimIndent(), + RequestStatus.WARNING + ), + Arguments.of( + """ + { + "patient": "4711", + "issues": [ + { "severity": "info", "message": "Info Message" } + ] + } + """.trimIndent(), + RequestStatus.SUCCESS + ) + ) + } + } + } \ No newline at end of file