diff --git a/.run/Debug TI.run.xml b/.run/Debug TI.run.xml new file mode 100644 index 000000000..b184afed7 --- /dev/null +++ b/.run/Debug TI.run.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/.secrets.baseline b/.secrets.baseline index 957518746..087a2360a 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -138,7 +138,7 @@ "filename": "README.md", "hashed_secret": "367e3228ed16bf72b36de9a4134ee8b825cafacb", "is_verified": false, - "line_number": 279, + "line_number": 285, "is_secret": false }, { @@ -146,7 +146,7 @@ "filename": "README.md", "hashed_secret": "40bd7d88eae0468b048e62e1056ac390970b2b51", "is_verified": false, - "line_number": 284, + "line_number": 290, "is_secret": false }, { @@ -154,7 +154,7 @@ "filename": "README.md", "hashed_secret": "0d46754ae17642645ca041edaac9a1c1569f5edc", "is_verified": false, - "line_number": 289, + "line_number": 295, "is_secret": false } ], @@ -269,5 +269,6 @@ } ] }, - "generated_at": "2024-02-09T17:58:04Z" + "generated_at": "2024-02-09T23:44:14Z" + } diff --git a/README.md b/README.md index a57ace32f..d985746ef 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,12 @@ the swarm parameters for the test and the local url where the app is running ### Debugging +#### Attached JVM Config for IntelliJ +The project comes with an attached remote jvm configuration for debuging the container. +If you check your remote JVM settings, under `Run/Edit Configurations`, +you will see the `Debug TI`. If you want to add a new remote JVM configuration, follow the steps below, +under "**Docker Container Debugging Using Java Debug Wire Protocal**" + #### Docker Container Debugging Using Java Debug Wire Protocal (JDWP) Go into the `Dockerfile` file and change `CMD ["java", "-jar", "app.jar"]` to `CMD ["java", "-agentlib:jdwp=transport=dt_socket,address=*:6006,server=y,suspend=n", "-jar", "app.jar"]` diff --git a/e2e/src/test/groovy/gov/hhs/cdc/trustedintermediary/e2e/OrderTest.groovy b/e2e/src/test/groovy/gov/hhs/cdc/trustedintermediary/e2e/OrderTest.groovy index c9aed9572..6b875f141 100644 --- a/e2e/src/test/groovy/gov/hhs/cdc/trustedintermediary/e2e/OrderTest.groovy +++ b/e2e/src/test/groovy/gov/hhs/cdc/trustedintermediary/e2e/OrderTest.groovy @@ -40,6 +40,27 @@ class OrderTest extends Specification { parsedSentPayload.entry[24].resource.contact.name.text.contains("SADIE S SMITH") } + def "check that ETOR processing code is added to the order before sending to report stream"() { + given: + var loginFirst = true + def expectedSystem = "http://localcodes.org/ETOR" + def expectedCode = "ETOR" + def expectedDisplay = "Processed by ETOR" + + when: + orderClient.submit(labOrderJsonFileString, submissionId, loginFirst) + def sentPayload = SentPayloadReader.read() + def parsedSentPayLoad = JsonParsing.parse(sentPayload) + def actualSystem = parsedSentPayLoad.entry[0].resource.meta.tag[1].system + def actualCode = parsedSentPayLoad.entry[0].resource.meta.tag[1].code + def actualDisplay = parsedSentPayLoad.entry[0].resource.meta.tag[1].display + + then: + actualSystem == expectedSystem + actualCode == expectedCode + actualDisplay == expectedDisplay + } + def "check that the rest of the message is unchanged except the parts we changed"() { when: orderClient.submit(labOrderJsonFileString, submissionId, true) @@ -48,10 +69,11 @@ class OrderTest extends Specification { def parsedLabOrderJsonFile = JsonParsing.parse(labOrderJsonFileString) then: - //test that everything else is the same except the MessageHeader's event and Patient contact + //test that everything else is the same except the MessageHeader's event, Patient contact, and etor processing tag parsedSentPayload.entry[0].resource.remove("eventCoding") parsedLabOrderJsonFile.entry[0].resource.remove("eventCoding") parsedSentPayload.entry[24].resource.remove("contact") + parsedSentPayload.entry[0].resource.meta.tag.remove(1) parsedSentPayload == parsedLabOrderJsonFile } diff --git a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/EtorDomainRegistration.java b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/EtorDomainRegistration.java index 02784bc95..7bf334846 100644 --- a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/EtorDomainRegistration.java +++ b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/EtorDomainRegistration.java @@ -25,13 +25,16 @@ import gov.hhs.cdc.trustedintermediary.etor.orders.SendOrderUseCase; import gov.hhs.cdc.trustedintermediary.etor.results.Result; import gov.hhs.cdc.trustedintermediary.etor.results.ResultController; +import gov.hhs.cdc.trustedintermediary.etor.results.ResultConverter; import gov.hhs.cdc.trustedintermediary.etor.results.ResultResponse; import gov.hhs.cdc.trustedintermediary.etor.results.ResultSender; import gov.hhs.cdc.trustedintermediary.etor.results.SendResultUseCase; import gov.hhs.cdc.trustedintermediary.external.database.DatabasePartnerMetadataStorage; import gov.hhs.cdc.trustedintermediary.external.database.DbDao; import gov.hhs.cdc.trustedintermediary.external.database.PostgresDao; +import gov.hhs.cdc.trustedintermediary.external.hapi.HapiMessageConverterHelper; import gov.hhs.cdc.trustedintermediary.external.hapi.HapiOrderConverter; +import gov.hhs.cdc.trustedintermediary.external.hapi.HapiResultConverter; import gov.hhs.cdc.trustedintermediary.external.localfile.FilePartnerMetadataStorage; import gov.hhs.cdc.trustedintermediary.external.localfile.MockRSEndpointClient; import gov.hhs.cdc.trustedintermediary.external.reportstream.ReportStreamEndpointClient; @@ -91,22 +94,30 @@ public class EtorDomainRegistration implements DomainConnector { @Override public Map> domainRegistration() { + // Demographics ApplicationContext.register( PatientDemographicsController.class, PatientDemographicsController.getInstance()); ApplicationContext.register( ConvertAndSendDemographicsUsecase.class, ConvertAndSendDemographicsUsecase.getInstance()); + // Orders ApplicationContext.register(OrderConverter.class, HapiOrderConverter.getInstance()); ApplicationContext.register(OrderController.class, OrderController.getInstance()); ApplicationContext.register(SendOrderUseCase.class, SendOrderUseCase.getInstance()); ApplicationContext.register(OrderSender.class, ReportStreamOrderSender.getInstance()); - ApplicationContext.register( - PartnerMetadataOrchestrator.class, PartnerMetadataOrchestrator.getInstance()); - ApplicationContext.register(ResultSender.class, ReportStreamResultSender.getInstance()); + // Results + ApplicationContext.register(ResultConverter.class, HapiResultConverter.getInstance()); ApplicationContext.register(ResultController.class, ResultController.getInstance()); ApplicationContext.register(SendResultUseCase.class, SendResultUseCase.getInstance()); + ApplicationContext.register(ResultSender.class, ReportStreamResultSender.getInstance()); + // Message + ApplicationContext.register( + HapiMessageConverterHelper.class, HapiMessageConverterHelper.getInstance()); ApplicationContext.register( ReportStreamSenderHelper.class, ReportStreamSenderHelper.getInstance()); + // Metadata + ApplicationContext.register( + PartnerMetadataOrchestrator.class, PartnerMetadataOrchestrator.getInstance()); if (ApplicationContext.getProperty("DB_URL") != null) { ApplicationContext.register(DbDao.class, PostgresDao.getInstance()); diff --git a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/metadata/EtorMetadataStep.java b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/metadata/EtorMetadataStep.java index 267d3d188..780a87d1a 100644 --- a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/metadata/EtorMetadataStep.java +++ b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/metadata/EtorMetadataStep.java @@ -1,12 +1,10 @@ package gov.hhs.cdc.trustedintermediary.etor.metadata; -/** Etor specific steps from the general shared metadata steps */ +/** Etor specific steps from the general shared metadata steps. Keep enum in alphabetical order */ public enum EtorMetadataStep { - RECEIVED_FROM_REPORT_STREAM, - - ORDER_CONVERTED_TO_OML, - CONTACT_SECTION_ADDED_TO_PATIENT, - + ETOR_PROCESSING_TAG_ADDED_TO_MESSAGE_HEADER, + ORDER_CONVERTED_TO_OML, + RECEIVED_FROM_REPORT_STREAM, SENT_TO_REPORT_STREAM } diff --git a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/orders/OrderConverter.java b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/orders/OrderConverter.java index 9bb674530..8ab155978 100644 --- a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/orders/OrderConverter.java +++ b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/orders/OrderConverter.java @@ -12,6 +12,8 @@ public interface OrderConverter { Order addContactSectionToPatientResource(Order order); + Order addEtorProcessingTag(Order message); + FhirMetadata extractPublicMetadataToOperationOutcome( PartnerMetadata metadata, String requestedId); } diff --git a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/orders/SendOrderUseCase.java b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/orders/SendOrderUseCase.java index fc5e52b7c..fe3edc360 100644 --- a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/orders/SendOrderUseCase.java +++ b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/orders/SendOrderUseCase.java @@ -34,6 +34,11 @@ public void convertAndSend(final Order order, String receivedSubmissionId) omlOrder = converter.addContactSectionToPatientResource(omlOrder); metadata.put(order.getFhirResourceId(), EtorMetadataStep.CONTACT_SECTION_ADDED_TO_PATIENT); + omlOrder = converter.addEtorProcessingTag(omlOrder); + metadata.put( + order.getFhirResourceId(), + EtorMetadataStep.ETOR_PROCESSING_TAG_ADDED_TO_MESSAGE_HEADER); + String sentSubmissionId = sender.send(omlOrder).orElse(null); saveSentOrderSubmissionId(receivedSubmissionId, sentSubmissionId); diff --git a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/results/ResultConverter.java b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/results/ResultConverter.java new file mode 100644 index 000000000..d63603338 --- /dev/null +++ b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/results/ResultConverter.java @@ -0,0 +1,6 @@ +package gov.hhs.cdc.trustedintermediary.etor.results; + +/** Interface for converting things to results and things in results. */ +public interface ResultConverter { + Result addEtorProcessingTag(Result message); +} diff --git a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/results/SendResultUseCase.java b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/results/SendResultUseCase.java index b8129559f..4e921013b 100644 --- a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/results/SendResultUseCase.java +++ b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/results/SendResultUseCase.java @@ -7,6 +7,9 @@ /** Use case for converting and sending a lab result message. */ public class SendResultUseCase implements SendMessageUseCase> { private static final SendResultUseCase INSTANCE = new SendResultUseCase(); + + @Inject ResultConverter converter; + @Inject ResultSender sender; private SendResultUseCase() {} @@ -17,6 +20,13 @@ public static SendResultUseCase getInstance() { @Override public void convertAndSend(Result result) throws UnableToSendMessageException { - sender.send(result); + + // savePartnerMetadataForReceivedResult(receivedSubmissionId, result) + var convertedResult = converter.addEtorProcessingTag(result); + // metadata.put(result.getFhirResourceId(), + // EtorMetadataStep.ETOR_PROCESSING_TAG_ADDED_TO_MESSAGE_HEADER); + sender.send(convertedResult); // var bundleId = sender.send(convertedResult).orElse(null), + // thoughts? + // saveSentResultSubmissionId(receivedSubmissionId, bundleId) } } diff --git a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/external/hapi/HapiMessageConverterHelper.java b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/external/hapi/HapiMessageConverterHelper.java new file mode 100644 index 000000000..188c2230b --- /dev/null +++ b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/external/hapi/HapiMessageConverterHelper.java @@ -0,0 +1,55 @@ +package gov.hhs.cdc.trustedintermediary.external.hapi; + +import gov.hhs.cdc.trustedintermediary.wrappers.Logger; +import javax.inject.Inject; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Coding; +import org.hl7.fhir.r4.model.MessageHeader; +import org.hl7.fhir.r4.model.Meta; + +/** + * Helper class with a variety of utilities to use on a FHIR bundle message. It adds the 'ETOR' tag + * to a FHIR bundle of type: OML, ORU It also creates the messageHeader resource in a FHIR bundle + * message. + */ +public class HapiMessageConverterHelper { + + private static final HapiMessageConverterHelper INSTANCE = new HapiMessageConverterHelper(); + + public static HapiMessageConverterHelper getInstance() { + return INSTANCE; + } + + @Inject Logger logger; + + private HapiMessageConverterHelper() {} + + /** + * Adds the `ETOR` code to any message provided + * + * @param messageBundle the in coming message in a FHIR bundle + */ + public void addEtorTagToBundle(Bundle messageBundle) { + var messageHeader = findOrInitializeMessageHeader(messageBundle); + var meta = messageHeader.hasMeta() ? messageHeader.getMeta() : new Meta(); + + meta.addTag(new Coding("http://localcodes.org/ETOR", "ETOR", "Processed by ETOR")); + messageHeader.setMeta(meta); + } + + /** + * Checks if the FHIR bundle has a messageHeader, and it creates one if it is missing + * + * @param bundle the in coming message in a FHIR bundle + * @return returns existing MessageHeader resource or a newly created one + */ + public MessageHeader findOrInitializeMessageHeader(Bundle bundle) { + var messageHeader = + HapiHelper.resourcesInBundle(bundle, MessageHeader.class).findFirst().orElse(null); + if (messageHeader == null) { + messageHeader = new MessageHeader(); + bundle.addEntry(new Bundle.BundleEntryComponent().setResource(messageHeader)); + } + return messageHeader; + } +} diff --git a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/external/hapi/HapiOrderConverter.java b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/external/hapi/HapiOrderConverter.java index ec247b993..b4691c243 100644 --- a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/external/hapi/HapiOrderConverter.java +++ b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/external/hapi/HapiOrderConverter.java @@ -45,6 +45,8 @@ public class HapiOrderConverter implements OrderConverter { @Inject Logger logger; + @Inject HapiMessageConverterHelper hapiMessageConverterHelper; + public static HapiOrderConverter getInstance() { return INSTANCE; } @@ -99,16 +101,7 @@ public Order convertToOmlOrder(Order order) { var hapiOrder = (Order) order; var orderBundle = hapiOrder.getUnderlyingOrder(); - - var messageHeader = - HapiHelper.resourcesInBundle(orderBundle, MessageHeader.class) - .findFirst() - .orElse(null); - - if (messageHeader == null) { - messageHeader = new MessageHeader(); - orderBundle.addEntry(new Bundle.BundleEntryComponent().setResource(messageHeader)); - } + var messageHeader = hapiMessageConverterHelper.findOrInitializeMessageHeader(orderBundle); messageHeader.setEvent(OML_CODING); @@ -152,13 +145,12 @@ private MessageHeader createMessageHeader() { messageHeader.setEvent(OML_CODING); - messageHeader.setMeta( - new Meta() - .addTag( - new Coding( - "http://terminology.hl7.org/CodeSystem/v2-0103", - "P", - "Production"))); + var meta = new Meta(); + + // Adding processing id of 'P' + meta.addTag("http://terminology.hl7.org/CodeSystem/v2-0103", "P", "Production"); + + messageHeader.setMeta(meta); messageHeader.setSource( new MessageHeader.MessageSourceComponent( @@ -168,6 +160,16 @@ private MessageHeader createMessageHeader() { return messageHeader; } + @Override + public Order addEtorProcessingTag(Order message) { + var hapiOrder = (Order) message; + var messageBundle = hapiOrder.getUnderlyingOrder(); + + hapiMessageConverterHelper.addEtorTagToBundle(messageBundle); + + return new HapiOrder(messageBundle); + } + private ServiceRequest createServiceRequest(final Patient patient, final Date orderDateTime) { logger.logInfo("Creating new ServiceRequest"); diff --git a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/external/hapi/HapiResultConverter.java b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/external/hapi/HapiResultConverter.java new file mode 100644 index 000000000..ed7c9a21e --- /dev/null +++ b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/external/hapi/HapiResultConverter.java @@ -0,0 +1,36 @@ +package gov.hhs.cdc.trustedintermediary.external.hapi; + +import gov.hhs.cdc.trustedintermediary.etor.results.Result; +import gov.hhs.cdc.trustedintermediary.etor.results.ResultConverter; +import gov.hhs.cdc.trustedintermediary.wrappers.Logger; +import javax.inject.Inject; +import org.hl7.fhir.r4.model.Bundle; + +/** + * Converts {@link Result} to a Hapi-specific FHIR lab result {@link Result }) with proper + * identifying message headers. + */ +public class HapiResultConverter implements ResultConverter { + + private static final HapiResultConverter INSTANCE = new HapiResultConverter(); + + @Inject HapiMessageConverterHelper hapiMessageConverterHelper; + + @Inject Logger logger; + + public static HapiResultConverter getInstance() { + return INSTANCE; + } + + private HapiResultConverter() {} + + @Override + public Result addEtorProcessingTag(final Result message) { + var hapiResult = (Result) message; + var messageBundle = hapiResult.getUnderlyingResult(); + + hapiMessageConverterHelper.addEtorTagToBundle(messageBundle); + + return new HapiResult(messageBundle); + } +} diff --git a/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/orders/SendOrderUseCaseTest.groovy b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/orders/SendOrderUseCaseTest.groovy index 95101318a..3961eaa85 100644 --- a/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/orders/SendOrderUseCaseTest.groovy +++ b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/orders/SendOrderUseCaseTest.groovy @@ -46,9 +46,11 @@ class SendOrderUseCaseTest extends Specification { then: 1 * mockConverter.convertToOmlOrder(mockOrder) >> mockOmlOrder 1 * mockConverter.addContactSectionToPatientResource(mockOmlOrder) >> mockOmlOrder + 1 * mockConverter.addEtorProcessingTag(mockOmlOrder) >> mockOmlOrder 1 * mockSender.send(mockOmlOrder) >> Optional.of(sentSubmissionId) 1 * sendOrder.metadata.put(_, EtorMetadataStep.ORDER_CONVERTED_TO_OML) 1 * sendOrder.metadata.put(_, EtorMetadataStep.CONTACT_SECTION_ADDED_TO_PATIENT) + 1 * sendOrder.metadata.put(_, EtorMetadataStep.ETOR_PROCESSING_TAG_ADDED_TO_MESSAGE_HEADER) 1 * mockOrchestrator.updateMetadataForReceivedOrder(receivedSubmissionId, _ as String) 1 * mockOrchestrator.updateMetadataForSentOrder(receivedSubmissionId, sentSubmissionId) } @@ -93,6 +95,7 @@ class SendOrderUseCaseTest extends Specification { 1 * mockLogger.logError(_, _) 1 * mockConverter.convertToOmlOrder(order) >> omlOrder 1 * mockConverter.addContactSectionToPatientResource(omlOrder) >> omlOrder + 1 * mockConverter.addEtorProcessingTag(omlOrder) >> omlOrder 1 * mockSender.send(omlOrder) >> Optional.of("sentId") } @@ -110,6 +113,7 @@ class SendOrderUseCaseTest extends Specification { then: 1 * mockConverter.convertToOmlOrder(order) >> omlOrder 1 * mockConverter.addContactSectionToPatientResource(omlOrder) >> omlOrder + 1 * mockConverter.addEtorProcessingTag(omlOrder) >> omlOrder 1 * mockSender.send(omlOrder) >> Optional.of("sentId") 1 * mockLogger.logError(_, partnerMetadataException) } diff --git a/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/results/SendResultUseCaseTest.groovy b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/results/SendResultUseCaseTest.groovy index f56fa4ea2..3c1928918 100644 --- a/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/results/SendResultUseCaseTest.groovy +++ b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/results/SendResultUseCaseTest.groovy @@ -9,23 +9,26 @@ import spock.lang.Specification class SendResultUseCaseTest extends Specification { def mockSender = Mock(ResultSender) + def mockConverter = Mock(ResultConverter) def setup() { TestApplicationContext.reset() TestApplicationContext.init() TestApplicationContext.register(SendMessageUseCase, SendResultUseCase.getInstance()) + TestApplicationContext.register(ResultConverter, mockConverter) TestApplicationContext.register(ResultSender, mockSender) + TestApplicationContext.injectRegisteredImplementations() } def "convertAndSend works"() { given: def mockResult = new ResultMock(null, "Mock result") - TestApplicationContext.injectRegisteredImplementations() when: SendResultUseCase.getInstance().convertAndSend(mockResult) then: + 1 * mockConverter.addEtorProcessingTag(mockResult) >> mockResult 1 * mockSender.send(mockResult) >> Optional.empty() noExceptionThrown() } @@ -33,7 +36,6 @@ class SendResultUseCaseTest extends Specification { def "convertAndSend throws exception when send fails"() { given: mockSender.send(_) >> { throw new UnableToSendMessageException("DogCow", new NullPointerException()) } - TestApplicationContext.injectRegisteredImplementations() when: SendResultUseCase.getInstance().convertAndSend(Mock(Result)) diff --git a/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/external/hapi/HapiMessageConverterHelperTest.groovy b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/external/hapi/HapiMessageConverterHelperTest.groovy new file mode 100644 index 000000000..ff255114b --- /dev/null +++ b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/external/hapi/HapiMessageConverterHelperTest.groovy @@ -0,0 +1,98 @@ +package gov.hhs.cdc.trustedintermediary.external.hapi + + +import gov.hhs.cdc.trustedintermediary.context.TestApplicationContext +import org.hl7.fhir.r4.model.* +import spock.lang.Specification + +class HapiMessageConverterHelperTest extends Specification { + + Bundle mockBundle + Patient mockPatient + + def setup() { + mockBundle = null + TestApplicationContext.reset() + TestApplicationContext.init() + TestApplicationContext.register(HapiMessageConverterHelper, HapiMessageConverterHelper.getInstance()) + TestApplicationContext.injectRegisteredImplementations() + + mockPatient = new Patient() + mockBundle = new Bundle().addEntry(new Bundle.BundleEntryComponent().setResource(mockPatient)) + } + + def "addEtorTag adds the ETOR message header tag to any Bundle"() { + given: + def expectedSystem = "http://localcodes.org/ETOR" + def expectedCode = "ETOR" + def expectedDisplay = "Processed by ETOR" + + def messageHeader = new MessageHeader() + messageHeader.setId(UUID.randomUUID().toString()) + def messageHeaderEntry = new Bundle.BundleEntryComponent().setResource(messageHeader) + mockBundle.getEntry().add(messageHeaderEntry) + + when: + HapiMessageConverterHelper.getInstance().addEtorTagToBundle(mockBundle) as Bundle + + then: + def messageHeaders = mockBundle.getEntry().get(1).getResource() as MessageHeader + def actualMessageTag = messageHeaders.getMeta().getTag()[0] + + actualMessageTag.getSystem() == expectedSystem + actualMessageTag.getCode() == expectedCode + actualMessageTag.getDisplay() == expectedDisplay + } + + def "addEtorTag adds the ETOR message header tag to any Bundle when message header is missing"() { + given: + def expectedSystem = "http://localcodes.org/ETOR" + def expectedCode = "ETOR" + def expectedDisplay = "Processed by ETOR" + + when: + HapiMessageConverterHelper.getInstance().addEtorTagToBundle(mockBundle) as Bundle + + then: + def messageHeaders = mockBundle.getEntry().get(1).getResource() as MessageHeader + def actualMessageTag = messageHeaders.getMeta().getTag()[0] + + actualMessageTag.getSystem() == expectedSystem + actualMessageTag.getCode() == expectedCode + actualMessageTag.getDisplay() == expectedDisplay + } + + def "addEtorTag adds the ETOR message header tag to any Bundle with existing Meta tag"() { + given: + def firstExpectedSystem = "a system" + def firstExpectedCode = "test" + def firstExpectedDisplay = "Processed by tests" + def secondExpectedSystem = "http://localcodes.org/ETOR" + def secondExpectedCode = "ETOR" + def secondExpectedDisplay = "Processed by ETOR" + + def messageHeader = new MessageHeader() + messageHeader.setId(UUID.randomUUID().toString()) + def meta = new Meta() + meta.addTag(new Coding(firstExpectedSystem, firstExpectedCode, firstExpectedDisplay)) + messageHeader.setMeta(meta) + def messageHeaderEntry = new Bundle.BundleEntryComponent().setResource(messageHeader) + mockBundle.getEntry().add(messageHeaderEntry) + + when: + HapiMessageConverterHelper.getInstance().addEtorTagToBundle(mockBundle) as Bundle + + then: + def messageHeaders = mockBundle.getEntry().get(1).getResource() as MessageHeader + def firstActualMessageTag = messageHeaders.getMeta().getTag()[0] + def secondActualMessageTag = messageHeaders.getMeta().getTag()[1] + + firstActualMessageTag.getSystem() == firstExpectedSystem + firstActualMessageTag.getCode() == firstExpectedCode + firstActualMessageTag.getDisplay() == firstExpectedDisplay + + secondActualMessageTag.getSystem() == secondExpectedSystem + secondActualMessageTag.getCode() == secondExpectedCode + secondActualMessageTag.getDisplay() == secondExpectedDisplay + } +} diff --git a/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/external/hapi/HapiOrderConverterTest.groovy b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/external/hapi/HapiOrderConverterTest.groovy index 8050d709e..340ca5507 100644 --- a/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/external/hapi/HapiOrderConverterTest.groovy +++ b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/external/hapi/HapiOrderConverterTest.groovy @@ -35,6 +35,7 @@ class HapiOrderConverterTest extends Specification { TestApplicationContext.reset() TestApplicationContext.init() TestApplicationContext.register(OrderConverter, HapiOrderConverter.getInstance()) + TestApplicationContext.register(HapiMessageConverterHelper, HapiMessageConverterHelper.getInstance()) TestApplicationContext.injectRegisteredImplementations() mockPatient = new Patient() @@ -227,6 +228,32 @@ class HapiOrderConverterTest extends Specification { contactSectionAddress.getPostalCode() == convertedPatientAddress.getPostalCode() } + def "add etor processing tag to messageHeader resource"() { + given: + def expectedSystem = "http://localcodes.org/ETOR" + def expectedCode = "ETOR" + def expectedDisplay = "Processed by ETOR" + + def messageHeader = new MessageHeader() + messageHeader.setId(UUID.randomUUID().toString()) + def messageHeaderEntry = new Bundle.BundleEntryComponent().setResource(messageHeader) + mockOrderBundle.getEntry().add(1, messageHeaderEntry) + mockOrder.getUnderlyingOrder() >> mockOrderBundle + + when: + def convertedOrderBundle = HapiOrderConverter.getInstance().addEtorProcessingTag(mockOrder).getUnderlyingOrder() as Bundle + + then: + def messageHeaders = convertedOrderBundle.getEntry().get(1).getResource() as MessageHeader + def actualSystem = messageHeaders.getMeta().getTag()[0].getSystem() + def actualCode = messageHeaders.getMeta().getTag()[0].getCode() + def actualDisplay = messageHeaders.getMeta().getTag()[0].getDisplay() + actualSystem == expectedSystem + actualCode == expectedCode + actualDisplay == expectedDisplay + } + + def "no humanName section in contact"() { given: def addHumanName = false diff --git a/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/external/hapi/HapiResultConverterTest.groovy b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/external/hapi/HapiResultConverterTest.groovy new file mode 100644 index 000000000..a143d6631 --- /dev/null +++ b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/external/hapi/HapiResultConverterTest.groovy @@ -0,0 +1,54 @@ +package gov.hhs.cdc.trustedintermediary.external.hapi + + +import gov.hhs.cdc.trustedintermediary.ResultMock +import gov.hhs.cdc.trustedintermediary.context.TestApplicationContext +import gov.hhs.cdc.trustedintermediary.etor.results.Result +import gov.hhs.cdc.trustedintermediary.etor.results.ResultConverter +import org.hl7.fhir.r4.model.Bundle +import org.hl7.fhir.r4.model.MessageHeader +import org.hl7.fhir.r4.model.Patient +import spock.lang.Specification + +class HapiResultConverterTest extends Specification { + Bundle mockResultBundle + Patient mockPatient + Result mockResult + + def setup() { + TestApplicationContext.reset() + TestApplicationContext.init() + TestApplicationContext.register(ResultConverter, HapiResultConverter.getInstance()) + TestApplicationContext.register(HapiMessageConverterHelper, HapiMessageConverterHelper.getInstance()) + TestApplicationContext.injectRegisteredImplementations() + + mockPatient = new Patient() + mockResultBundle = new Bundle().addEntry(new Bundle.BundleEntryComponent().setResource(mockPatient)) + mockResult = new ResultMock("mockFhirResourceId", mockResultBundle) + } + + def "add etor processing tag to messageHeader resource"() { + given: + def expectedSystem = "http://localcodes.org/ETOR" + def expectedCode = "ETOR" + def expectedDisplay = "Processed by ETOR" + + def messageHeader = new MessageHeader() + messageHeader.setId(UUID.randomUUID().toString()) + def messageHeaderEntry = new Bundle.BundleEntryComponent().setResource(messageHeader) + mockResultBundle.getEntry().add(1, messageHeaderEntry) + mockResult.getUnderlyingResult() >> mockResultBundle + + when: + def convertedResultBundle = HapiResultConverter.getInstance().addEtorProcessingTag(mockResult).getUnderlyingResult() as Bundle + + then: + def messageHeaders = convertedResultBundle.getEntry().get(1).getResource() as MessageHeader + def actualSystem = messageHeaders.getMeta().getTag()[0].getSystem() + def actualCode = messageHeaders.getMeta().getTag()[0].getCode() + def actualDisplay = messageHeaders.getMeta().getTag()[0].getDisplay() + actualSystem == expectedSystem + actualCode == expectedCode + actualDisplay == expectedDisplay + } +} diff --git a/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/external/hapi/HapiResultTest.groovy b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/external/hapi/HapiResultTest.groovy new file mode 100644 index 000000000..f40ada0ba --- /dev/null +++ b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/external/hapi/HapiResultTest.groovy @@ -0,0 +1,31 @@ +package gov.hhs.cdc.trustedintermediary.external.hapi + +import org.hl7.fhir.r4.model.Bundle +import spock.lang.Specification + +class HapiResultTest extends Specification{ + def "getUnderlyingResult works"() { + given: + def expectedResult = new Bundle() + def result = new HapiResult(expectedResult) + + when: + def actualResult = result.getUnderlyingResult() + + then: + actualResult == expectedResult + } + + def "getFhirResourceId works"() { + given: + def expectId = "fhirResourceId" + def innerResult = new Bundle() + innerResult.setId(expectId) + + when: + def actualResult = new HapiResult(innerResult) + + then: + actualResult.getFhirResourceId() == expectId + } +}