From e49b834a8374f98e56f6faddd0b0ccef456ec3cb Mon Sep 17 00:00:00 2001 From: victor-chaparro <117938212+victor-chaparro@users.noreply.github.com> Date: Wed, 29 Jan 2025 09:03:35 -0700 Subject: [PATCH] Revert "MessageTesting API filter errors (#17142)" This reverts commit 253f7703965d15df6bcf5fdf3c258df197226335. --- .../src/main/kotlin/azure/ReportFunction.kt | 2 +- .../main/kotlin/cli/ProcessFhirCommands.kt | 203 ++++++-------- .../fhirengine/engine/FHIRReceiverFilter.kt | 2 +- .../translation/hl7/utils/FhirPathUtils.kt | 2 +- .../kotlin/cli/ProcessFhirCommandsTests.kt | 263 ------------------ 5 files changed, 88 insertions(+), 384 deletions(-) delete mode 100644 prime-router/src/test/kotlin/cli/ProcessFhirCommandsTests.kt diff --git a/prime-router/src/main/kotlin/azure/ReportFunction.kt b/prime-router/src/main/kotlin/azure/ReportFunction.kt index 2c806949d33..00a2b8294ea 100644 --- a/prime-router/src/main/kotlin/azure/ReportFunction.kt +++ b/prime-router/src/main/kotlin/azure/ReportFunction.kt @@ -233,7 +233,7 @@ class ReportFunction( override var enrichmentSchemaWarnings: MutableList = mutableListOf(), override var receiverTransformErrors: MutableList = mutableListOf(), override var receiverTransformWarnings: MutableList = mutableListOf(), - override var filterErrors: MutableList = mutableListOf(), + override var filterErrors: MutableList = mutableListOf(), ) : ProcessFhirCommands.MessageOrBundleParent() /** diff --git a/prime-router/src/main/kotlin/cli/ProcessFhirCommands.kt b/prime-router/src/main/kotlin/cli/ProcessFhirCommands.kt index f3678ed176c..73012d84748 100644 --- a/prime-router/src/main/kotlin/cli/ProcessFhirCommands.kt +++ b/prime-router/src/main/kotlin/cli/ProcessFhirCommands.kt @@ -22,7 +22,7 @@ import gov.cdc.prime.router.Metadata import gov.cdc.prime.router.MimeFormat import gov.cdc.prime.router.Receiver import gov.cdc.prime.router.Report -import gov.cdc.prime.router.ReportStreamFilterType +import gov.cdc.prime.router.ReportStreamFilter import gov.cdc.prime.router.Topic import gov.cdc.prime.router.azure.BlobAccess import gov.cdc.prime.router.azure.ConditionStamper @@ -41,16 +41,15 @@ import gov.cdc.prime.router.cli.CommandUtilities.Companion.abort import gov.cdc.prime.router.cli.helpers.HL7DiffHelper import gov.cdc.prime.router.common.Environment import gov.cdc.prime.router.common.JacksonMapperUtilities +import gov.cdc.prime.router.config.validation.OrganizationValidation import gov.cdc.prime.router.fhirengine.config.HL7TranslationConfig import gov.cdc.prime.router.fhirengine.engine.FHIRReceiverFilter -import gov.cdc.prime.router.fhirengine.engine.FHIRReceiverFilter.FhirExpressionEvaluationResult import gov.cdc.prime.router.fhirengine.engine.FHIRReceiverFilter.ReceiverFilterEvaluationResult import gov.cdc.prime.router.fhirengine.engine.encodePreserveEncodingChars import gov.cdc.prime.router.fhirengine.translation.HL7toFhirTranslator import gov.cdc.prime.router.fhirengine.translation.hl7.FhirToHl7Context import gov.cdc.prime.router.fhirengine.translation.hl7.FhirToHl7Converter import gov.cdc.prime.router.fhirengine.translation.hl7.FhirTransformer -import gov.cdc.prime.router.fhirengine.translation.hl7.SchemaException import gov.cdc.prime.router.fhirengine.translation.hl7.utils.CustomContext import gov.cdc.prime.router.fhirengine.translation.hl7.utils.FhirPathUtils import gov.cdc.prime.router.fhirengine.utils.FhirTranscoder @@ -210,7 +209,7 @@ class ProcessFhirCommands : CliktCommand( (outputFormat == MimeFormat.FHIR.toString()) || (receiver != null && receiver.format == MimeFormat.FHIR) ) -> { - val fhirMessage = convertHl7ToFhir(contents).first + val fhirMessage = convertHl7ToFhir(contents, receiver).first messageOrBundle.bundle = fhirMessage handleSendAndReceiverFhirEnrichments(messageOrBundle, receiver, senderSchema, isCli) @@ -254,7 +253,7 @@ class ProcessFhirCommands : CliktCommand( (receiver.format == MimeFormat.HL7 || receiver.format == MimeFormat.HL7_BATCH) ) ) -> { - val (bundle2, inputMessage) = convertHl7ToFhir(contents) + val (bundle2, inputMessage) = convertHl7ToFhir(contents, receiver) messageOrBundle.bundle = bundle2 handleSendAndReceiverFhirEnrichments(messageOrBundle, receiver, senderSchema, isCli) @@ -284,7 +283,7 @@ class ProcessFhirCommands : CliktCommand( senderSchema: String?, isCli: Boolean, ) { - stampObservations(messageOrBundle) + stampObservations(messageOrBundle, receiver) val senderSchemaName = when { senderSchema != null -> senderSchema @@ -294,9 +293,7 @@ class ProcessFhirCommands : CliktCommand( handleSenderTransforms(messageOrBundle, senderSchemaName) - if (receiver != null && messageOrBundle.bundle != null) { - handleReceiverFilters(receiver, messageOrBundle, isCli) - } + evaluateReceiverFilters(receiver, messageOrBundle, isCli) val receiverEnrichmentSchemaNames = when { receiver != null && receiver.enrichmentSchemaNames.isNotEmpty() -> { @@ -326,120 +323,58 @@ class ProcessFhirCommands : CliktCommand( } } - fun handleReceiverFilters(receiver: Receiver, messageOrBundle: MessageOrBundle, isCli: Boolean) { - if (messageOrBundle.bundle?.identifier?.value == null) { - // this is just for logging so it is fine to just make it up - messageOrBundle.bundle?.identifier?.setValue(UUID.randomUUID().toString()) - } - // TODO: https://github.com/CDCgov/prime-reportstream/issues/16407 - val fhirReceiverFilter = FHIRReceiverFilter(reportStreamEventService = NoopReportStreamEventService()) - - evaluateReceiverFilters(receiver, messageOrBundle, fhirReceiverFilter) - - applyConditionFilter(receiver, messageOrBundle, fhirReceiverFilter) - - if (isCli && messageOrBundle.filterErrors.isNotEmpty()) { - val errorMsgLines = messageOrBundle.filterErrors.map { filterError -> - "${filterError.filterType} - ${filterError.message} : \n ${filterError.filter}" - } - throw CliktError(errorMsgLines.joinToString("\n")) - } - } - - fun evaluateReceiverFilters( - receiver: Receiver, - messageOrBundle: MessageOrBundle, - fhirReceiverFilter: FHIRReceiverFilter, - ) { - val bundle = messageOrBundle.bundle!! - val actionLogger = ActionLogger() - - // filter groups for looped evaluation - condition filter evaluated separately - val fhirFilters = listOf( - Pair(receiver.jurisdictionalFilter, ReportStreamFilterType.JURISDICTIONAL_FILTER), - Pair(receiver.qualityFilter, ReportStreamFilterType.QUALITY_FILTER), - Pair(receiver.routingFilter, ReportStreamFilterType.ROUTING_FILTER), - Pair(receiver.processingModeFilter, ReportStreamFilterType.PROCESSING_MODE_FILTER), - ) - - fhirFilters.forEach { - val filter = it.first - val filterType = it.second - try { - val result = fhirReceiverFilter.evaluateFhirExpressionFilters( - receiver, - bundle, - actionLogger, - bundle.identifier.value, - filter, - filterType - ) - if (result is FhirExpressionEvaluationResult.Failure) { - messageOrBundle.filterErrors.add( - FilterError( - result.failingFilter.filters.joinToString("\n"), - "Filter failed", - filterType.toString() + private fun evaluateReceiverFilters(receiver: Receiver?, messageOrBundle: MessageOrBundle, isCli: Boolean) { + if (receiver != null && messageOrBundle.bundle != null) { + val reportStreamFilters = mutableListOf>() + reportStreamFilters.add(Pair("Jurisdictional Filter", receiver.jurisdictionalFilter)) + reportStreamFilters.add(Pair("Quality Filter", receiver.qualityFilter)) + reportStreamFilters.add(Pair("Routing Filter", receiver.routingFilter)) + reportStreamFilters.add(Pair("Processing Mode Filter", receiver.processingModeFilter)) + + reportStreamFilters.forEach { reportStreamFilter -> + reportStreamFilter.second.forEach { filter -> + val validation = OrganizationValidation.validateFilter(filter) + if (!validation) { + messageOrBundle.filterErrors.add( + "Filter of type ${reportStreamFilter.first} is not valid. " + + "Value: '$filter'" ) - ) + } else { + val result = FhirPathUtils.evaluate( + CustomContext( + messageOrBundle.bundle!!, + messageOrBundle.bundle!!, + mutableMapOf(), + CustomFhirPathFunctions() + ), + messageOrBundle.bundle!!, + messageOrBundle.bundle!!, + filter + ) + if (result.isEmpty() || + (result[0].isBooleanPrimitive && result[0].primitiveValue() == "false") + ) { + messageOrBundle.filterErrors.add( + "Filter '$filter' filtered out everything, nothing to return." + ) + } + } } - } catch (e: Exception) { - messageOrBundle.filterErrors.add( - FilterError( - filter.joinToString("\n"), - "Invalid filter - ${e.message}", - filterType.toString() - ) - ) } - } - } - - fun applyConditionFilter( - receiver: Receiver, - messageOrBundle: MessageOrBundle, - fhirReceiverFilter: FHIRReceiverFilter, - ) { - val bundle = messageOrBundle.bundle!! - try { - val result = fhirReceiverFilter.evaluateObservationConditionFilters( - receiver, - bundle, - ActionLogger(), - bundle.identifier.value - ) + receiver.conditionFilter.forEach { conditionFilter -> + val validation = OrganizationValidation.validateFilter(conditionFilter) + if (!validation) { + messageOrBundle.filterErrors.add("Condition filter '$conditionFilter' is not valid.") + } + } - if (result is ReceiverFilterEvaluationResult.Success) { - // update the bundle since observations might have gotten pruned after condition filter evaluation - messageOrBundle.bundle = result.bundle - } else { - result as ReceiverFilterEvaluationResult.Failure - messageOrBundle.filterErrors.add( - FilterError( - result.failingFilter.filters.joinToString("\n"), - "Filter failed", - result.failingFilter.filterType.toString() - ) - ) + if (isCli && messageOrBundle.filterErrors.isNotEmpty()) { + throw CliktError(messageOrBundle.filterErrors.joinToString("\n")) } - } catch (e: SchemaException) { - messageOrBundle.filterErrors.add( - FilterError( - receiver.conditionFilter.joinToString("\n"), - "Invalid filter - ${e.message}", - ReportStreamFilterType.CONDITION_FILTER.toString() - ) - ) } } - data class FilterError( - val filter: String, - val message: String, - val filterType: String, - ) - abstract class MessageOrBundleParent( open var senderTransformErrors: MutableList = mutableListOf(), open var senderTransformWarnings: MutableList = mutableListOf(), @@ -447,7 +382,7 @@ class ProcessFhirCommands : CliktCommand( open var enrichmentSchemaWarnings: MutableList = mutableListOf(), open var receiverTransformErrors: MutableList = mutableListOf(), open var receiverTransformWarnings: MutableList = mutableListOf(), - open var filterErrors: MutableList = mutableListOf(), + open var filterErrors: MutableList = mutableListOf(), ) class MessageOrBundle( @@ -459,10 +394,34 @@ class ProcessFhirCommands : CliktCommand( override var enrichmentSchemaWarnings: MutableList = mutableListOf(), override var receiverTransformErrors: MutableList = mutableListOf(), override var receiverTransformWarnings: MutableList = mutableListOf(), - override var filterErrors: MutableList = mutableListOf(), + override var filterErrors: MutableList = mutableListOf(), ) : MessageOrBundleParent() - private fun getReceiver( + private fun applyConditionFilter(receiver: Receiver, bundle: Bundle): Bundle { + val trackingId = if (bundle.id != null) { + bundle.id + } else { + // this is just for logging so it is fine to just make it up + UUID.randomUUID().toString() + } + // TODO: https://github.com/CDCgov/prime-reportstream/issues/16407 + val result = + FHIRReceiverFilter( + reportStreamEventService = NoopReportStreamEventService() + ).evaluateObservationConditionFilters( + receiver, + bundle, + ActionLogger(), + trackingId + ) + if (result is ReceiverFilterEvaluationResult.Success) { + return result.bundle + } else { + throw CliktError("Condition filter failed.") + } + } + + fun getReceiver( environment: Environment, receiverName: String?, orgName: String?, @@ -548,11 +507,15 @@ class ProcessFhirCommands : CliktCommand( private fun stampObservations( messageOrBundle: MessageOrBundle, + receiver: Receiver?, ) { val stamper = ConditionStamper(LookupTableConditionMapper(Metadata.getInstance())) messageOrBundle.bundle?.getObservations()?.forEach { observation -> stamper.stampObservation(observation) } + if (receiver != null) { + messageOrBundle.bundle = applyConditionFilter(receiver, messageOrBundle.bundle!!) + } } /** @@ -563,7 +526,7 @@ class ProcessFhirCommands : CliktCommand( * look like. * @return a FHIR bundle and the parsed HL7 input that represents the data in the one HL7 message */ - private fun convertHl7ToFhir(hl7String: String): Pair { + private fun convertHl7ToFhir(hl7String: String, receiver: Receiver?): Pair { val hasFiveEncodingChars = hl7MessageHasFiveEncodingChars(hl7String) // Some HL7 2.5.1 implementations have adopted the truncation character # that was added in 2.7 // However, the library used to encode the HL7 message throws an error it there are more than 4 encoding @@ -587,6 +550,10 @@ class ProcessFhirCommands : CliktCommand( stamper.stampObservation(observation) } + if (receiver != null) { + fhirMessage = applyConditionFilter(receiver, fhirMessage) + } + return Pair(fhirMessage, hl7message) } diff --git a/prime-router/src/main/kotlin/fhirengine/engine/FHIRReceiverFilter.kt b/prime-router/src/main/kotlin/fhirengine/engine/FHIRReceiverFilter.kt index 8506ec0b3c3..4f9a0998923 100644 --- a/prime-router/src/main/kotlin/fhirengine/engine/FHIRReceiverFilter.kt +++ b/prime-router/src/main/kotlin/fhirengine/engine/FHIRReceiverFilter.kt @@ -282,7 +282,7 @@ class FHIRReceiverFilter( * * [actionLogger], [trackingId], and [filterType] facilitate logging */ - fun evaluateFhirExpressionFilters( + private fun evaluateFhirExpressionFilters( receiver: Receiver, bundle: Bundle, actionLogger: ActionLogger, diff --git a/prime-router/src/main/kotlin/fhirengine/translation/hl7/utils/FhirPathUtils.kt b/prime-router/src/main/kotlin/fhirengine/translation/hl7/utils/FhirPathUtils.kt index 4c6a995b89a..b1689acd6ea 100644 --- a/prime-router/src/main/kotlin/fhirengine/translation/hl7/utils/FhirPathUtils.kt +++ b/prime-router/src/main/kotlin/fhirengine/translation/hl7/utils/FhirPathUtils.kt @@ -145,7 +145,7 @@ object FhirPathUtils : Logging { } } catch (e: Exception) { val msg = when (e) { - is FHIRLexer.FHIRLexerException -> "Syntax error: ${e.message} in FHIR Path expression $expression" + is FHIRLexer.FHIRLexerException -> "Syntax error in FHIR Path expression $expression" is SchemaException -> e.message.toString() else -> "Unknown error while evaluating FHIR Path expression $expression for condition. " + diff --git a/prime-router/src/test/kotlin/cli/ProcessFhirCommandsTests.kt b/prime-router/src/test/kotlin/cli/ProcessFhirCommandsTests.kt deleted file mode 100644 index 953e06dbe7a..00000000000 --- a/prime-router/src/test/kotlin/cli/ProcessFhirCommandsTests.kt +++ /dev/null @@ -1,263 +0,0 @@ -package cli - -import assertk.assertThat -import assertk.assertions.isEmpty -import assertk.assertions.isEqualTo -import assertk.assertions.isNotEmpty -import assertk.assertions.isNotNull -import com.github.ajalt.clikt.core.CliktError -import gov.cdc.prime.router.CustomerStatus -import gov.cdc.prime.router.Hl7Configuration -import gov.cdc.prime.router.Metadata -import gov.cdc.prime.router.Receiver -import gov.cdc.prime.router.ReportStreamFilter -import gov.cdc.prime.router.ReportStreamFilterType -import gov.cdc.prime.router.Topic -import gov.cdc.prime.router.cli.NoopReportStreamEventService -import gov.cdc.prime.router.cli.ProcessFhirCommands -import gov.cdc.prime.router.fhirengine.engine.FHIRReceiverFilter -import gov.cdc.prime.router.fhirengine.utils.FhirTranscoder -import gov.cdc.prime.router.unittest.UnitTestUtils -import io.mockk.every -import io.mockk.mockkObject -import org.hl7.fhir.r4.model.Patient -import org.junit.jupiter.api.assertThrows -import java.io.File -import kotlin.test.Test - - class ProcessFhirCommandsTests { - - private val jurisdictionalFilter: ReportStreamFilter = listOf( - "(Bundle.entry.resource.ofType(ServiceRequest)[0].requester.resolve().organization.resolve().address.state " + - "= 'ME') or (Bundle.entry.resource.ofType(Patient).address.state = 'ME')" - ) - private val qualityFilter: ReportStreamFilter = listOf( - "Bundle.entry.resource.ofType(Patient).birthDate.exists()", - "Bundle.entry.resource.ofType(Patient).name.family.exists()" - ) - private val receiverHl7Configuration = Hl7Configuration( - schemaName = "classpath:/metadata/hl7_mapping/receivers/STLTs/ME/ME-receiver-transform.yml", - useTestProcessingMode = true, - useBatchHeaders = true, - messageProfileId = "", - receivingApplicationName = "", - receivingFacilityOID = "", - receivingFacilityName = "", - receivingApplicationOID = "", - receivingOrganization = "" - ) - private val receiver = Receiver( - "full-elr", - "me-phd", - Topic.FULL_ELR, - CustomerStatus.ACTIVE, - receiverHl7Configuration, - jurisdictionalFilter = jurisdictionalFilter, - qualityFilter = qualityFilter - ) - - private val testFile = File("src/testIntegration/resources/datatests/FHIR_to_HL7/sample_ME_20240806-0001.fhir") - private val fhirString = testFile.inputStream().readBytes().toString(Charsets.UTF_8) - - @Test - fun handleReceiverFilters() { - mockkObject(Metadata) - every { Metadata.getInstance() } returns UnitTestUtils.simpleMetadata - val bundle = FhirTranscoder.decode(fhirString) - val messageOrBundle = ProcessFhirCommands.MessageOrBundle() - messageOrBundle.bundle = bundle - - // test missing bundle id - messageOrBundle.bundle?.identifier?.setValue(null) - ProcessFhirCommands().handleReceiverFilters(receiver, messageOrBundle, false) - assertThat(messageOrBundle.bundle?.identifier?.value).isNotNull() - - // remove birthdate to make quality filter fail - val patient = bundle.entry.first { it.resource.resourceType.name == "Patient" }.resource as Patient - patient.birthDate = null - - // reset filterErrors and test CliKtError thrown when isCli = true - messageOrBundle.filterErrors = mutableListOf() - val cliError = assertThrows { - ProcessFhirCommands().handleReceiverFilters(receiver, messageOrBundle, true) - } - assertThat(cliError.message).isEqualTo( - "QUALITY_FILTER - Filter failed : \n Bundle.entry.resource.ofType(Patient).birthDate.exists()" - ) - } - - @Test - fun evaluateReceiverFilters() { - mockkObject(Metadata) - every { Metadata.getInstance() } returns UnitTestUtils.simpleMetadata - val bundle = FhirTranscoder.decode(fhirString) - val messageOrBundle = ProcessFhirCommands.MessageOrBundle() - messageOrBundle.bundle = bundle - val fhirReceiverFilter = FHIRReceiverFilter(reportStreamEventService = NoopReportStreamEventService()) - - ProcessFhirCommands().evaluateReceiverFilters(receiver, messageOrBundle, fhirReceiverFilter) - - assertThat(messageOrBundle.filterErrors).isEmpty() - } - - @Test - fun `evaluateReceiverFilters - with filter errors`() { - mockkObject(Metadata) - every { Metadata.getInstance() } returns UnitTestUtils.simpleMetadata - val bundle = FhirTranscoder.decode(fhirString) - - // remove birthdate to make quality filter fail - val patient = bundle.entry.first { it.resource.resourceType.name == "Patient" }.resource as Patient - patient.birthDate = null - - val messageOrBundle = ProcessFhirCommands.MessageOrBundle() - messageOrBundle.bundle = bundle - - val fhirReceiverFilter = FHIRReceiverFilter(reportStreamEventService = NoopReportStreamEventService()) - // Test filter error fields - ProcessFhirCommands().evaluateReceiverFilters(receiver, messageOrBundle, fhirReceiverFilter) - assertThat(messageOrBundle.filterErrors).isNotEmpty() - val qualityFilterError = messageOrBundle.filterErrors.filter { - it.filterType == ReportStreamFilterType.QUALITY_FILTER.toString() - } - assertThat(qualityFilterError.count()).isEqualTo(1) - assertThat(qualityFilterError.first().filter) - .isEqualTo("Bundle.entry.resource.ofType(Patient).birthDate.exists()") - assertThat(qualityFilterError.first().message).isEqualTo("Filter failed") - - // Test multiple filters failed - val receiver2 = Receiver( - "full-elr", - "me-phd", - Topic.FULL_ELR, - CustomerStatus.ACTIVE, - receiverHl7Configuration, - jurisdictionalFilter = listOf("Bundle.entry.resource.ofType(Patient).address.state = 'IG'"), - qualityFilter = qualityFilter, - ) - - messageOrBundle.filterErrors = mutableListOf() - ProcessFhirCommands().evaluateReceiverFilters(receiver2, messageOrBundle, fhirReceiverFilter) - assertThat( - messageOrBundle.filterErrors.filter { - it.filterType == ReportStreamFilterType.QUALITY_FILTER.toString() - } - ).isNotEmpty() - assertThat( - messageOrBundle.filterErrors.filter { - it.filterType == ReportStreamFilterType.JURISDICTIONAL_FILTER.toString() - } - ).isNotEmpty() - - // Test invalid filter - val invalidFilter = "Bundle.entry.resource.ofType(MessageHeader).meta.tag" - val receiver3 = Receiver( - "full-elr", - "me-phd", - Topic.FULL_ELR, - CustomerStatus.ACTIVE, - receiverHl7Configuration, - qualityFilter = qualityFilter, - processingModeFilter = listOf(invalidFilter) - ) - - messageOrBundle.filterErrors = mutableListOf() - ProcessFhirCommands().evaluateReceiverFilters(receiver3, messageOrBundle, fhirReceiverFilter) - - val processingFilterError = messageOrBundle.filterErrors.filter { - it.filterType == ReportStreamFilterType.PROCESSING_MODE_FILTER.toString() - } - assertThat(processingFilterError).isNotEmpty() - assertThat(processingFilterError.first().filter).isEqualTo(invalidFilter) - assertThat(processingFilterError.first().message).isEqualTo( - "Invalid filter - FHIR Path expression did not evaluate to a boolean type: Bundle.entry.resource." + - "ofType(MessageHeader).meta.tag" - ) - } - - @Test - fun applyConditionFilters() { - mockkObject(Metadata) - every { Metadata.getInstance() } returns UnitTestUtils.simpleMetadata - val bundle = FhirTranscoder.decode(fhirString) - val messageOrBundle = ProcessFhirCommands.MessageOrBundle() - messageOrBundle.bundle = bundle - val fhirReceiverFilter = FHIRReceiverFilter(reportStreamEventService = NoopReportStreamEventService()) - - ProcessFhirCommands().applyConditionFilter(receiver, messageOrBundle, fhirReceiverFilter) - assertThat(messageOrBundle.filterErrors).isEmpty() - - val conditionFilter: ReportStreamFilter = listOf( - "%resource.code.coding.extension('https://reportstream.cdc.gov/fhir/StructureDefinition/condition-code')" + - ".value.where(code in ('840539006')).exists()" - ) - - val receiver2 = Receiver( - "full-elr", - "me-phd", - Topic.FULL_ELR, - CustomerStatus.ACTIVE, - receiverHl7Configuration, - conditionFilter = conditionFilter - ) - ProcessFhirCommands().applyConditionFilter(receiver2, messageOrBundle, fhirReceiverFilter) - assertThat(messageOrBundle.filterErrors).isEmpty() - } - - @Test - fun `applyConditionFilters - with filter errors`() { - mockkObject(Metadata) - every { Metadata.getInstance() } returns UnitTestUtils.simpleMetadata - val bundle = FhirTranscoder.decode(fhirString) - val messageOrBundle = ProcessFhirCommands.MessageOrBundle() - messageOrBundle.bundle = bundle - val fhirReceiverFilter = FHIRReceiverFilter(reportStreamEventService = NoopReportStreamEventService()) - - val zeroConditionFilter: ReportStreamFilter = listOf( - "%resource.code.coding.extension('https://reportstream.cdc.gov/fhir/StructureDefinition/condition-code')" + - ".value.where(code in ('0000000')).exists()" - ) - - val receiver2 = Receiver( - "full-elr", - "me-phd", - Topic.FULL_ELR, - CustomerStatus.ACTIVE, - receiverHl7Configuration, - conditionFilter = zeroConditionFilter - ) - - ProcessFhirCommands().applyConditionFilter(receiver2, messageOrBundle, fhirReceiverFilter) - - val conditionFilterError = messageOrBundle.filterErrors.filter { - it.filterType == ReportStreamFilterType.CONDITION_FILTER.toString() - } - assertThat(conditionFilterError).isNotEmpty() - assertThat(conditionFilterError.first().filter).isEqualTo(zeroConditionFilter.first()) - assertThat(conditionFilterError.first().message).isEqualTo("Filter failed") - - val invalidConditionFilter: ReportStreamFilter = listOf("%resource.code.coding.") - - val receiver3 = Receiver( - "full-elr", - "me-phd", - Topic.FULL_ELR, - CustomerStatus.ACTIVE, - receiverHl7Configuration, - conditionFilter = invalidConditionFilter - ) - messageOrBundle.filterErrors = mutableListOf() - - ProcessFhirCommands().applyConditionFilter(receiver3, messageOrBundle, fhirReceiverFilter) - - val conditionFilterError2 = messageOrBundle.filterErrors.filter { - it.filterType == ReportStreamFilterType.CONDITION_FILTER.toString() - } - assertThat(conditionFilterError2).isNotEmpty() - assertThat(conditionFilterError2.first().filter).isEqualTo(invalidConditionFilter.first()) - assertThat(conditionFilterError2.first().message).isEqualTo( - "Invalid filter - Syntax error: Error in ?? at 1, 1: Expression terminated unexpectedly in " + - "FHIR Path expression %resource.code.coding." - ) - } -} \ No newline at end of file