diff --git a/build.gradle b/build.gradle index 3402e5eca..79987aca2 100644 --- a/build.gradle +++ b/build.gradle @@ -54,8 +54,8 @@ dependencies { implementation 'org.apache.httpcomponents:httpclient:4.5.12' implementation 'com.heroku.sdk:env-keystore:1.1.11' - implementation 'ca.uhn.hapi.fhir:hapi-fhir-base:4.2.0' - implementation 'ca.uhn.hapi.fhir:hapi-fhir-structures-r4:4.2.0' + implementation 'ca.uhn.hapi.fhir:hapi-fhir-base:8.0.0' + implementation 'ca.uhn.hapi.fhir:hapi-fhir-structures-r4:8.0.0' implementation 'ca.uhn.hapi.fhir:hapi-fhir-validation-resources-r4:8.0.0' implementation 'com.google.guava:guava:33.4.8-jre' implementation 'org.apache.qpid:qpid-jms-client:2.7.0' diff --git a/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/inbound/InboundMeshQueueMultiTransactionTest.java b/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/inbound/InboundMeshQueueMultiTransactionTest.java index 375c8f2dd..8432b30ed 100644 --- a/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/inbound/InboundMeshQueueMultiTransactionTest.java +++ b/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/inbound/InboundMeshQueueMultiTransactionTest.java @@ -1,8 +1,11 @@ package uk.nhs.digital.nhsconnect.nhais.inbound; import org.assertj.core.api.SoftAssertions; +import org.json.JSONException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.skyscreamer.jsonassert.JSONAssert; +import org.skyscreamer.jsonassert.JSONCompareMode; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.core.io.Resource; @@ -100,7 +103,7 @@ void setUp() { } @Test - void whenMeshInboundQueueRegistrationMessageIsReceived_thenMessageIsHandled(SoftAssertions softly) throws IOException, JMSException { + void whenMeshInboundQueueRegistrationMessageIsReceived_thenMessageIsHandled(SoftAssertions softly) throws IOException, JMSException, JSONException { var meshMessage = new MeshMessage() .setWorkflowId(WorkflowId.REGISTRATION) .setContent(new String(Files.readAllBytes(interchange.getFile().toPath()))); @@ -148,10 +151,10 @@ private void assertOutboundRecepMessage(SoftAssertions softly) throws IOExceptio softly.assertThat(meshMessage.getMessageSentTimestamp()).isNull(); } - private void assertGpSystemInboundQueueMessages(SoftAssertions softly) throws JMSException, IOException { + private void assertGpSystemInboundQueueMessages(SoftAssertions softly) throws JMSException, IOException, JSONException { var gpSystemInboundQueueMessages = IntStream.range(0, 6) .mapToObj(x -> getGpSystemInboundQueueMessage()) - .collect(Collectors.toList()); + .toList(); assertGpSystemInboundQueueMessages( softly, gpSystemInboundQueueMessages.get(0), MESSAGE_1_TRANSACTION_TYPE, TRANSACTION_1_OPERATION_ID, fhirTN1); @@ -172,7 +175,7 @@ private void assertGpSystemInboundQueueMessages( Message message, ReferenceTransactionType.TransactionType expectedTransactionType, String expectedOperationId, - Resource expectedFhir) throws JMSException, IOException { + Resource expectedFhir) throws JMSException, IOException, JSONException { // all transactions come from the same interchange and use the same conversation id String conversationId = message.getStringProperty("ConversationId"); @@ -185,8 +188,12 @@ private void assertGpSystemInboundQueueMessages( .isEqualTo(expectedOperationId); softly.assertThat(message.getStringProperty("TransactionType")) .isEqualTo(expectedTransactionType.name().toLowerCase()); - softly.assertThat(parseTextMessage(message)) - .isEqualTo(new String(Files.readAllBytes(expectedFhir.getFile().toPath()))); + + JSONAssert.assertEquals( + parseTextMessage(message), + new String(Files.readAllBytes(expectedFhir.getFile().toPath())), + JSONCompareMode.STRICT + ); } private void assertInboundStates(SoftAssertions softly, List inboundStates) { diff --git a/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/inbound/InboundMeshQueueRegistrationTest.java b/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/inbound/InboundMeshQueueRegistrationTest.java index 00176a607..64c4770e3 100644 --- a/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/inbound/InboundMeshQueueRegistrationTest.java +++ b/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/inbound/InboundMeshQueueRegistrationTest.java @@ -1,8 +1,11 @@ package uk.nhs.digital.nhsconnect.nhais.inbound; import org.assertj.core.api.SoftAssertions; +import org.json.JSONException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.skyscreamer.jsonassert.JSONAssert; +import org.skyscreamer.jsonassert.JSONCompareMode; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.core.io.Resource; @@ -63,7 +66,7 @@ void setUp() { } @Test - void whenMeshInboundQueueRegistrationMessageIsReceived_thenMessageIsHandled(SoftAssertions softly) throws IOException, JMSException { + void whenMeshInboundQueueRegistrationMessageIsReceived_thenMessageIsHandled(SoftAssertions softly) throws IOException, JMSException, JSONException { var meshMessage = new MeshMessage() .setWorkflowId(WorkflowId.REGISTRATION) .setContent(new String(Files.readAllBytes(interchange.getFile().toPath()))) @@ -86,14 +89,15 @@ private void assertOutboundRecepMessage(SoftAssertions softly) throws IOExceptio softly.assertThat(meshMessage.getMessageSentTimestamp()).isNull(); } - private void assertGpSystemInboundQueueMessage(SoftAssertions softly) throws JMSException, IOException { + private void assertGpSystemInboundQueueMessage(SoftAssertions softly) throws JMSException, IOException, JSONException { var message = getGpSystemInboundQueueMessage(); var content = parseTextMessage(message); var expectedContent = new String(Files.readAllBytes(fhir.getFile().toPath())); softly.assertThat(message.getStringProperty("OperationId")).isEqualTo(OPERATION_ID); softly.assertThat(message.getStringProperty("TransactionType")).isEqualTo(TRANSACTION_TYPE.name().toLowerCase()); - softly.assertThat(content).isEqualTo(expectedContent); + + JSONAssert.assertEquals(expectedContent, content, JSONCompareMode.STRICT); } private void assertInboundState(SoftAssertions softly) { diff --git a/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/inbound/InboundUserAcceptanceTest.java b/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/inbound/InboundUserAcceptanceTest.java index af8e9f29f..1582bd26e 100644 --- a/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/inbound/InboundUserAcceptanceTest.java +++ b/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/inbound/InboundUserAcceptanceTest.java @@ -1,10 +1,13 @@ package uk.nhs.digital.nhsconnect.nhais.inbound; +import org.json.JSONException; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import org.skyscreamer.jsonassert.JSONAssert; +import org.skyscreamer.jsonassert.JSONCompareMode; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.DirtiesContext; import uk.nhs.digital.nhsconnect.nhais.IntegrationBaseTest; @@ -20,6 +23,7 @@ import jakarta.jms.JMSException; import jakarta.jms.Message; + import java.util.List; import java.util.stream.Collectors; @@ -99,7 +103,7 @@ private void verifyThatCloseQuarterNotificationIsNotPresentOnGpSystemInboundQueu assertThat(gpSystemInboundQueueMessage).isNull(); } - private void verifyThatNonCloseQuarterNotificationMessageIsTranslated(TestData testData, Message gpSystemInboundQueueMessage) throws JMSException { + private void verifyThatNonCloseQuarterNotificationMessageIsTranslated(TestData testData, Message gpSystemInboundQueueMessage) throws JMSException, JSONException { assertThat(gpSystemInboundQueueMessage).isNotNull(); // assert transaction type in JMS header is correct assertMessageHeaders(gpSystemInboundQueueMessage, "fp69_prior_notification"); @@ -107,9 +111,9 @@ private void verifyThatNonCloseQuarterNotificationMessageIsTranslated(TestData t assertMessageBody(gpSystemInboundQueueMessage, testData.getJson()); } - private void assertMessageBody(Message gpSystemInboundQueueMessage, String expectedBody) throws JMSException { + private void assertMessageBody(Message gpSystemInboundQueueMessage, String expectedBody) throws JMSException, JSONException { var body = parseTextMessage(gpSystemInboundQueueMessage); - assertThat(body).isEqualTo(expectedBody); + JSONAssert.assertEquals(expectedBody, body, JSONCompareMode.STRICT); } private void assertMessageHeaders(Message gpSystemInboundQueueMessage, String expectedTransactionType) throws JMSException { diff --git a/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/outbound/controller/DeductionIntegrationTest.java b/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/outbound/controller/DeductionIntegrationTest.java index 8ec670ec5..523d56827 100644 --- a/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/outbound/controller/DeductionIntegrationTest.java +++ b/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/outbound/controller/DeductionIntegrationTest.java @@ -31,6 +31,12 @@ @DirtiesContext public class DeductionIntegrationTest { public static final String URL = "/fhir/Patient/$nhais.deduction"; + private static final String ATTRIBUTE_VALUE_MUST_NOT_BE_EMPTY = + "Invalid attribute value \"\": Attribute value must not be empty (\"\")"; + private static final String INVALID_VALUE_STRING_PARAMETER = + "Unable to parse JSON resource as a Parameters: HAPI-1821: [element=\"valueString\"] "; + private static final String INVALID_VALUE_PARAMETER = + "Unable to parse JSON resource as a Parameters: HAPI-1821: [element=\"value\"] "; @Autowired private MockMvc mockMvc; @@ -91,7 +97,8 @@ void whenEmptyNhsNumber_thenRespond400() throws Exception { .andExpect(status().isBadRequest()) .andReturn(); OperationOutcome operationOutcome = (OperationOutcome) fhirParser.parse(result.getResponse().getContentAsString()); - assertThat(operationOutcome.getIssueFirstRep().getDetails().getText()).contains("Unable to parse JSON resource as a Parameters: Invalid attribute value \"\": Attribute values must not be empty (\"\")"); + assertThat(operationOutcome.getIssueFirstRep().getDetails().getText()) + .contains(INVALID_VALUE_PARAMETER + ATTRIBUTE_VALUE_MUST_NOT_BE_EMPTY); } @Test @@ -131,7 +138,8 @@ void whenEmptyDateOfDeduction_thenRespond400() throws Exception { .andExpect(status().isBadRequest()) .andReturn(); OperationOutcome operationOutcome = (OperationOutcome) fhirParser.parse(result.getResponse().getContentAsString()); - assertThat(operationOutcome.getIssueFirstRep().getDetails().getText()).contains("Unable to parse JSON resource as a Parameters: Invalid attribute value \"\": Attribute values must not be empty (\"\")"); + assertThat(operationOutcome.getIssueFirstRep().getDetails().getText()) + .contains(INVALID_VALUE_STRING_PARAMETER + ATTRIBUTE_VALUE_MUST_NOT_BE_EMPTY); } @Test @@ -171,7 +179,8 @@ void whenEmptyReasonForDeduction_thenRespond400() throws Exception { .andExpect(status().isBadRequest()) .andReturn(); OperationOutcome operationOutcome = (OperationOutcome) fhirParser.parse(result.getResponse().getContentAsString()); - assertThat(operationOutcome.getIssueFirstRep().getDetails().getText()).contains("Unable to parse JSON resource as a Parameters: Invalid attribute value \"\": Attribute values must not be empty (\"\")"); + assertThat(operationOutcome.getIssueFirstRep().getDetails().getText()) + .contains(INVALID_VALUE_STRING_PARAMETER + ATTRIBUTE_VALUE_MUST_NOT_BE_EMPTY); } @Test @@ -194,4 +203,4 @@ void whenNullReasonForDeduction_thenRespond400() throws Exception { assertThat(operationOutcome.getIssueFirstRep().getDetails().getText()).contains(ParameterNames.DEDUCTION_REASON_CODE); } -} \ No newline at end of file +} diff --git a/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/outbound/controller/FhirControllerIntegrationTest.java b/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/outbound/controller/FhirControllerIntegrationTest.java index e0bc6deef..c3620ccc2 100644 --- a/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/outbound/controller/FhirControllerIntegrationTest.java +++ b/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/outbound/controller/FhirControllerIntegrationTest.java @@ -25,6 +25,12 @@ @AutoConfigureMockMvc @Slf4j public class FhirControllerIntegrationTest { + private static final String INVALID_VALUE_STRING_PARAMETER = + "Unable to parse JSON resource as a Parameters: HAPI-1821: [element=\"valueString\"] "; + private static final String INVALID_VALUE_PARAMETER = + "Unable to parse JSON resource as a Parameters: HAPI-1821: [element=\"value\"] "; + private static final String ATTRIBUTE_VALUE_MUST_NOT_BE_EMPTY = + "Invalid attribute value \"\": Attribute value must not be empty (\"\")"; @Autowired private MockMvc mockMvc; @@ -80,7 +86,7 @@ void whenDeductionNoDestinationHaCipher_thenRerturns400() throws Exception { .andReturn(); OperationOutcome operationOutcome = (OperationOutcome) fhirParser.parse(result.getResponse().getContentAsString()); assertThat(operationOutcome.getIssueFirstRep().getDetails().getText()) - .contains("Invalid attribute value \"\": Attribute values must not be empty"); + .contains(INVALID_VALUE_PARAMETER + ATTRIBUTE_VALUE_MUST_NOT_BE_EMPTY); } @Test @@ -91,7 +97,7 @@ void whenRemovalNoDestinationHaCipher_thenRerturns400() throws Exception { .andReturn(); OperationOutcome operationOutcome = (OperationOutcome) fhirParser.parse(result.getResponse().getContentAsString()); assertThat(operationOutcome.getIssueFirstRep().getDetails().getText()) - .contains("Invalid attribute value \"\": Attribute values must not be empty"); + .contains(INVALID_VALUE_PARAMETER + ATTRIBUTE_VALUE_MUST_NOT_BE_EMPTY); } @@ -103,7 +109,7 @@ void whenDeductionNoGpCode_thenReturns400() throws Exception { .andReturn(); OperationOutcome operationOutcome = (OperationOutcome) fhirParser.parse(result.getResponse().getContentAsString()); assertThat(operationOutcome.getIssueFirstRep().getDetails().getText()) - .contains("Invalid attribute value \"\": Attribute values must not be empty"); + .contains(INVALID_VALUE_PARAMETER + ATTRIBUTE_VALUE_MUST_NOT_BE_EMPTY); } @Test @@ -114,7 +120,7 @@ void whenRemovalNoGpCode_thenReturns400() throws Exception { .andReturn(); OperationOutcome operationOutcome = (OperationOutcome) fhirParser.parse(result.getResponse().getContentAsString()); assertThat(operationOutcome.getIssueFirstRep().getDetails().getText()) - .contains("Invalid attribute value \"\": Attribute values must not be empty"); + .contains(INVALID_VALUE_PARAMETER + ATTRIBUTE_VALUE_MUST_NOT_BE_EMPTY); } @Test @@ -125,7 +131,7 @@ void whenDeductionNpGpTradingPartnerCode_thenReturns400() throws Exception { .andReturn(); OperationOutcome operationOutcome = (OperationOutcome) fhirParser.parse(result.getResponse().getContentAsString()); assertThat(operationOutcome.getIssueFirstRep().getDetails().getText()) - .contains("Invalid attribute value \"\": Attribute values must not be empty"); + .contains(INVALID_VALUE_STRING_PARAMETER + ATTRIBUTE_VALUE_MUST_NOT_BE_EMPTY); } @Test @@ -136,7 +142,7 @@ void whenRemovalNpGpTradingPartnerCode_thenReturns400() throws Exception { .andReturn(); OperationOutcome operationOutcome = (OperationOutcome) fhirParser.parse(result.getResponse().getContentAsString()); assertThat(operationOutcome.getIssueFirstRep().getDetails().getText()) - .contains("Invalid attribute value \"\": Attribute values must not be empty"); + .contains(INVALID_VALUE_STRING_PARAMETER + ATTRIBUTE_VALUE_MUST_NOT_BE_EMPTY); } @Test diff --git a/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/outbound/controller/RemovalIntegrationTest.java b/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/outbound/controller/RemovalIntegrationTest.java index 783f71675..635e99231 100644 --- a/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/outbound/controller/RemovalIntegrationTest.java +++ b/src/intTest/java/uk/nhs/digital/nhsconnect/nhais/outbound/controller/RemovalIntegrationTest.java @@ -89,7 +89,11 @@ void whenEmptyNhsNumber_thenRespond400() throws Exception { .andExpect(status().isBadRequest()) .andReturn(); OperationOutcome operationOutcome = (OperationOutcome) fhirParser.parse(result.getResponse().getContentAsString()); - assertThat(operationOutcome.getIssueFirstRep().getDetails().getText()).contains("Unable to parse JSON resource as a Parameters: Invalid attribute value \"\": Attribute values must not be empty (\"\")"); + assertThat(operationOutcome.getIssueFirstRep().getDetails().getText()) + .contains( + "Unable to parse JSON resource as a Parameters: HAPI-1821: [element=\"value\"] " + + "Invalid attribute value \"\": Attribute value must not be empty (\"\")" + ); } diff --git a/src/main/java/uk/nhs/digital/nhsconnect/nhais/model/fhir/ParametersExtension.java b/src/main/java/uk/nhs/digital/nhsconnect/nhais/model/fhir/ParametersExtension.java index 29cef9063..45be7c2d9 100644 --- a/src/main/java/uk/nhs/digital/nhsconnect/nhais/model/fhir/ParametersExtension.java +++ b/src/main/java/uk/nhs/digital/nhsconnect/nhais/model/fhir/ParametersExtension.java @@ -1,7 +1,6 @@ package uk.nhs.digital.nhsconnect.nhais.model.fhir; import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.r4.model.Extension; import org.hl7.fhir.r4.model.Parameters; @@ -14,7 +13,6 @@ import java.util.Objects; import java.util.Optional; -import java.util.function.Supplier; @RequiredArgsConstructor public class ParametersExtension { @@ -79,19 +77,15 @@ public static Optional extractOptionalValue(Parameters parameters, Strin } public Optional extractOptionalValue(String name) { - return Optional.ofNullable(parameters.getParameter(name)) + return parameters.getParameter() + .stream() + .filter(p -> p.getName().equals(name)) + .findFirst() + .map(Parameters.ParametersParameterComponent::getValue) .map(StringType.class::cast) .map(StringType::getValueAsString); } - @SneakyThrows - public String extractValueOrThrow(String name, Supplier exception) { - return Optional.ofNullable(parameters.getParameter(name)) - .map(StringType.class::cast) - .map(StringType::getValueAsString) - .orElseThrow(exception); - } - public int size() { return parameters.getParameter().size(); }