From 351710e8dd178b0f99fbca8b698742d207a02e82 Mon Sep 17 00:00:00 2001 From: Mohammad Iqbal Date: Thu, 16 May 2024 16:22:27 +0100 Subject: [PATCH 1/8] [PRMT-4817] - Modified EhrRequestTest.java integration tests as required --- .../repo_incoming/EhrRequestTest.java | 426 +++++++++--------- .../utils/MessageParsingUtility.java | 23 + .../resources/application-test.properties | 2 +- .../LargeMessageFragmentHandlerTest.java | 4 +- 4 files changed, 248 insertions(+), 207 deletions(-) create mode 100644 src/integration/java/uk/nhs/prm/repo/ehrtransferservice/utils/MessageParsingUtility.java diff --git a/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java b/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java index bacfde48b..fb574206c 100644 --- a/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java +++ b/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java @@ -1,204 +1,222 @@ -//package uk.nhs.prm.repo.ehrtransferservice.repo_incoming; -// -//import com.github.tomakehurst.wiremock.junit5.WireMockTest; -//import org.junit.jupiter.api.AfterEach; -//import org.junit.jupiter.api.BeforeEach; -//import org.junit.jupiter.api.Test; -//import org.junit.jupiter.api.extension.ExtendWith; -//import org.mockito.ArgumentMatchers; -//import org.mockito.Mock; -//import org.mockito.Mockito; -//import org.slf4j.Logger; -//import org.slf4j.LoggerFactory; -//import org.springframework.beans.factory.annotation.Autowired; -//import org.springframework.beans.factory.annotation.Value; -//import org.springframework.boot.test.context.SpringBootTest; -//import org.springframework.boot.test.mock.mockito.MockBean; -//import org.springframework.test.context.ActiveProfiles; -//import org.springframework.test.context.ContextConfiguration; -//import org.springframework.test.context.junit.jupiter.SpringExtension; -//import uk.nhs.prm.repo.ehrtransferservice.activemq.ForceXercesParserExtension; -//import uk.nhs.prm.repo.ehrtransferservice.activemq.SimpleAmqpQueue; -//import uk.nhs.prm.repo.ehrtransferservice.configuration.LocalStackAwsConfig; -//import uk.nhs.prm.repo.ehrtransferservice.database.TransferService; -//import uk.nhs.prm.repo.ehrtransferservice.database.enumeration.ConversationTransferStatus; -//import uk.nhs.prm.repo.ehrtransferservice.database.model.ConversationRecord; -//import uk.nhs.prm.repo.ehrtransferservice.exceptions.database.ConversationNotPresentException; -//import uk.nhs.prm.repo.ehrtransferservice.models.confirmmessagestored.StoreMessageResponseBody; -//import uk.nhs.prm.repo.ehrtransferservice.services.ehr_repo.EhrRepoService; -//import uk.nhs.prm.repo.ehrtransferservice.services.ehr_repo.StoreMessageResult; -//import uk.nhs.prm.repo.ehrtransferservice.utils.SqsQueueUtility; -//import uk.nhs.prm.repo.ehrtransferservice.utils.TransferTrackerDbUtility; -// -//import java.util.UUID; -//import java.util.concurrent.TimeUnit; -// -//import static com.github.tomakehurst.wiremock.client.WireMock.*; -//import static org.awaitility.Awaitility.await; -//import static org.junit.jupiter.api.Assertions.assertEquals; -//import static org.mockito.Mockito.when; -//import static uk.nhs.prm.repo.ehrtransferservice.database.enumeration.ConversationTransferStatus.INBOUND_CONTINUE_REQUEST_SENT; -//import static uk.nhs.prm.repo.ehrtransferservice.database.enumeration.ConversationTransferStatus.INBOUND_REQUEST_SENT; -//import static uk.nhs.prm.repo.ehrtransferservice.database.enumeration.ConversationTransferStatus.INBOUND_TIMEOUT; -//import static uk.nhs.prm.repo.ehrtransferservice.database.enumeration.Layer.CONVERSATION; -//import static uk.nhs.prm.repo.ehrtransferservice.database.enumeration.TransferTableAttribute.DESTINATION_GP; -//import static uk.nhs.prm.repo.ehrtransferservice.utils.TestDataLoaderUtility.getTestDataAsString; -// -//@SpringBootTest -//@ActiveProfiles("test") -//@WireMockTest(httpPort = 8080) -//@ExtendWith(SpringExtension.class) -//@ExtendWith(ForceXercesParserExtension.class) -//@ContextConfiguration(classes = LocalStackAwsConfig.class) -//class EhrRequestTest { -// private static final Logger log = LoggerFactory.getLogger(EhrRequestTest.class); -// @Autowired -// private TransferService transferService; -// -// @Autowired -// private TransferTrackerDbUtility transferTrackerDbUtility; -// -// @Autowired -// private SqsQueueUtility sqsQueueUtility; -// -// @MockBean -// private EhrRepoService ehrRepoService; -// -// @Value("${aws.repoIncomingQueueName}") -// private String repoIncomingQueueName; -// -// @Value("${activemq.inboundQueue}") -// private String inboundQueue; -// -// @Value("${gp2gpMessengerAuthKey}") -// private String gp2gpMessengerAuthKey; -// -// private static final String NHS_NUMBER = "9798548754"; -// private static final UUID INBOUND_CONVERSATION_ID = UUID.fromString("ce3aad10-9b7c-4a9b-ab87-a9d6521d61b2"); -// private static final String NEMS_MESSAGE_ID = "eefe01f7-33aa-45ed-8aac-4e0cf68670fd"; -// private static final String NEMS_EVENT_LAST_UPDATED = "2017-11-01T15:00:33+00:00"; -// private static final String SOURCE_GP = "B14758"; -// -// @BeforeEach -// void beforeEach(@Value("${inboundTimeoutSeconds}") String inboundTimeoutSeconds) throws Exception { -// // reset the timeout to the default as it is redefined in some tests -// System.setProperty("inboundTimeoutSeconds", inboundTimeoutSeconds); -// } -// -// @AfterEach -// void afterEach() { -// sqsQueueUtility.purgeQueue(repoIncomingQueueName); -// transferTrackerDbUtility.deleteItem(INBOUND_CONVERSATION_ID, CONVERSATION); -// } -// -// @Test -// void Given_ValidRepoIncomingEvent_When_PublishedToRepoIncomingQueue_Then_CreateConversationAndUpdateStatusToInboundRequestSent() { -// // given -// final String repoIncomingMessage = getRepoIncomingMessage(); -// -// // when -// createStubForGp2GpMessengerEhrRequest(); -// sqsQueueUtility.sendSqsMessage(repoIncomingMessage, repoIncomingQueueName); -// -// // then -// waitForConversationTransferStatusMatching(INBOUND_REQUEST_SENT); -// } -// -// @Test -// void Given_ValidRepoIncomingEventForSmallEhr_When_NoEhrResponseReceived_Then_UpdateStatusToInboundTimeout() { -// // given -// // override inboundTimeoutSeconds so that the request will timeout within the timeframe -// System.setProperty("inboundTimeoutSeconds", "10"); -// -// final String repoIncomingMessage = getRepoIncomingMessage(); -// -// // when -// createStubForGp2GpMessengerEhrRequest(); -// sqsQueueUtility.sendSqsMessage(repoIncomingMessage, repoIncomingQueueName); -// waitForConversationTransferStatusMatching(INBOUND_REQUEST_SENT); -// -// -// // then -// waitForConversationTransferStatusMatching(INBOUND_TIMEOUT); -// } -// -// @Test -// void Given_ValidRepoIncomingEventForLargeEhr_When_CoreReceivedButNoFragments_Then_UpdateStatusToInboundTimeout() throws Exception { -// // given -// // override inboundTimeoutSeconds so that the request will timeout within the timeframe -// System.setProperty("inboundTimeoutSeconds", "10"); -// -// final SimpleAmqpQueue inboundQueueFromMhs = new SimpleAmqpQueue(inboundQueue); -// final String repoIncomingMessage = getRepoIncomingMessage(); -// final String largeEhrCore = getTestDataAsString("large-ehr-core"); -// -// // when -// createStubForGp2GpMessengerEhrRequest(); -// createStubForGp2GpMessengerContinueRequest(); -// createMockForEhrRepoStoreMessage(); -// -// sqsQueueUtility.sendSqsMessage(repoIncomingMessage, repoIncomingQueueName); -// waitForConversationTransferStatusMatching(INBOUND_REQUEST_SENT); -// -// inboundQueueFromMhs.sendMessage(largeEhrCore); -// waitForConversationTransferStatusMatching(INBOUND_CONTINUE_REQUEST_SENT); -// -// // TODO PRMT-4817 it's successfully sending the continue request but not timing out? -// // org.opentest4j.AssertionFailedError: expected: but was: -// -// // then -// waitForConversationTransferStatusMatching(INBOUND_TIMEOUT); -// } -// -// // Test specific helper methods -// private String getRepoIncomingMessage() { -// final String repoIncomingEvent = """ -// { -// "conversationId": "%s", -// "nhsNumber": "%s", -// "nemsMessageId": "%s", -// "sourceGp": "%s", -// "destinationGp": "%s", -// "nemsEventLastUpdated": "%s" -// } -// """; -// -// return repoIncomingEvent.formatted( -// INBOUND_CONVERSATION_ID.toString().toUpperCase(), -// NHS_NUMBER, -// NEMS_MESSAGE_ID, -// SOURCE_GP, -// DESTINATION_GP, -// NEMS_EVENT_LAST_UPDATED -// ); -// } -// -// private void createMockForEhrRepoStoreMessage() throws Exception { -// StoreMessageResult result = new StoreMessageResult(new StoreMessageResponseBody("complete")); -// when(ehrRepoService.storeMessage(Mockito.any())).thenReturn(result); -// } -// -// private void createStubForGp2GpMessengerEhrRequest() { -// stubFor(post(urlMatching("/health-record-requests/" + NHS_NUMBER)) -// .withHeader("Authorization", equalTo(gp2gpMessengerAuthKey)) -// .withHeader("Content-Type", equalTo("application/json")) -// .willReturn(aResponse().withStatus(204))); -// } -// -// private void createStubForGp2GpMessengerContinueRequest() { -// stubFor(post(urlMatching("/health-record-requests/continue-message")) -// .withHeader("Authorization", equalTo(gp2gpMessengerAuthKey)) -// .withHeader("Content-Type", equalTo("application/json")) -// .willReturn(aResponse().withStatus(204))); -// } -// -// private void waitForConversationTransferStatusMatching(ConversationTransferStatus transferStatus) { -// await().atMost(20, TimeUnit.SECONDS).untilAsserted(() -> { -// try { -// ConversationRecord record = transferService.getConversationByInboundConversationId(INBOUND_CONVERSATION_ID); -// log.info("The current status of the Conversation is: {}", record.state()); -// assertEquals(transferStatus.name(), record.state()); -// } catch (ConversationNotPresentException ignored) {} -// }); -// } -//} \ No newline at end of file +package uk.nhs.prm.repo.ehrtransferservice.repo_incoming; + +import com.github.tomakehurst.wiremock.junit5.WireMockTest; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import uk.nhs.prm.repo.ehrtransferservice.activemq.ForceXercesParserExtension; +import uk.nhs.prm.repo.ehrtransferservice.activemq.SimpleAmqpQueue; +import uk.nhs.prm.repo.ehrtransferservice.configuration.LocalStackAwsConfig; +import uk.nhs.prm.repo.ehrtransferservice.database.TransferService; +import uk.nhs.prm.repo.ehrtransferservice.database.enumeration.ConversationTransferStatus; +import uk.nhs.prm.repo.ehrtransferservice.database.model.ConversationRecord; +import uk.nhs.prm.repo.ehrtransferservice.utils.SqsQueueUtility; +import uk.nhs.prm.repo.ehrtransferservice.utils.TransferTrackerDbUtility; + +import java.io.IOException; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.put; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; +import static org.awaitility.Awaitility.await; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static uk.nhs.prm.repo.ehrtransferservice.database.enumeration.ConversationTransferStatus.INBOUND_COMPLETE; +import static uk.nhs.prm.repo.ehrtransferservice.database.enumeration.ConversationTransferStatus.INBOUND_CONTINUE_REQUEST_SENT; +import static uk.nhs.prm.repo.ehrtransferservice.database.enumeration.ConversationTransferStatus.INBOUND_REQUEST_SENT; +import static uk.nhs.prm.repo.ehrtransferservice.database.enumeration.ConversationTransferStatus.INBOUND_TIMEOUT; +import static uk.nhs.prm.repo.ehrtransferservice.database.enumeration.Layer.CONVERSATION; +import static uk.nhs.prm.repo.ehrtransferservice.database.enumeration.TransferTableAttribute.DESTINATION_GP; +import static uk.nhs.prm.repo.ehrtransferservice.utils.MessageParsingUtility.getMessageId; +import static uk.nhs.prm.repo.ehrtransferservice.utils.TestDataLoaderUtility.getTestDataAsString; + +@SpringBootTest +@ActiveProfiles("test") +@WireMockTest(httpPort = 8080) +@ExtendWith(SpringExtension.class) +@ExtendWith(ForceXercesParserExtension.class) +@ContextConfiguration(classes = LocalStackAwsConfig.class) +class EhrRequestTest { + private static final String NHS_NUMBER = "9798548754"; + private static final UUID INBOUND_CONVERSATION_ID = UUID.fromString("ce3aad10-9b7c-4a9b-ab87-a9d6521d61b2"); + private static final String NEMS_MESSAGE_ID = "eefe01f7-33aa-45ed-8aac-4e0cf68670fd"; + private static final String NEMS_EVENT_LAST_UPDATED = "2017-11-01T15:00:33+00:00"; + private static final String SOURCE_GP = "B14758"; + private static final String PRESIGNED_URL = "http://localhost:8080/presigned/url"; + + private static final String REPO_INCOMING_MESSAGE = getRepoIncomingMessage(); + + @Autowired + private TransferService transferService; + + @Autowired + private TransferTrackerDbUtility transferTrackerDbUtility; + + @Autowired + private SqsQueueUtility sqsQueueUtility; + + @Value("${aws.repoIncomingQueueName}") + private String repoIncomingQueueName; + + @Value("${activemq.inboundQueue}") + private String inboundQueue; + + @Value("${gp2gpMessengerAuthKey}") + private String gp2gpMessengerAuthKey; + + @Value("${ehrRepoAuthKey}") + private String ehrRepoAuthKey; + + @AfterEach + void afterEach() { + sqsQueueUtility.purgeQueue(repoIncomingQueueName); + transferService.updateConversationTransferStatus(INBOUND_CONVERSATION_ID, INBOUND_COMPLETE); + transferTrackerDbUtility.deleteItem(INBOUND_CONVERSATION_ID, CONVERSATION); + } + + @Test + void Given_ValidRepoIncomingEvent_When_PublishedToRepoIncomingQueue_Then_CreateConversationAndUpdateStatusToInboundRequestSent() { + // when + createStubForGp2GpMessengerEhrRequest(); + sqsQueueUtility.sendSqsMessage(REPO_INCOMING_MESSAGE, repoIncomingQueueName); + + // then + await().atMost(30, TimeUnit.SECONDS) + .untilAsserted(() -> assertTrue(conversationStatusMatches(INBOUND_CONVERSATION_ID, INBOUND_REQUEST_SENT))); + } + + @Test + void Given_ValidRepoIncomingEventForSmallEhr_When_NoEhrResponseReceived_Then_UpdateStatusToInboundTimeout() { + // when + createStubForGp2GpMessengerEhrRequest(); + sqsQueueUtility.sendSqsMessage(REPO_INCOMING_MESSAGE, repoIncomingQueueName); + + // then + await().atMost(30, TimeUnit.SECONDS) + .untilAsserted(() -> assertTrue(conversationStatusMatches(INBOUND_CONVERSATION_ID, INBOUND_TIMEOUT))); + } + + @Test + void Given_ValidRepoIncomingEventForLargeEhr_When_CoreReceivedButNoFragments_Then_UpdateStatusToInboundTimeout() throws IOException { + // given + final SimpleAmqpQueue mhsInboundQueue = new SimpleAmqpQueue(inboundQueue); + final String largeEhrCore = getTestDataAsString("large-ehr-core"); + final UUID messageId = getMessageId(largeEhrCore).orElseThrow(); + + // when + createStubForGp2GpMessengerEhrRequest(); + stubFetchStorageUrl(INBOUND_CONVERSATION_ID, messageId); + stubPresignedUrlUploadMessage(); + stubConfirmMessageStored("complete", 201); + createStubForGp2GpMessengerContinueRequest(); + + sqsQueueUtility.sendSqsMessage(REPO_INCOMING_MESSAGE, repoIncomingQueueName); + + await().atMost(30, TimeUnit.SECONDS) + .untilAsserted(() -> assertTrue(conversationStatusMatches(INBOUND_CONVERSATION_ID, INBOUND_REQUEST_SENT))); + + mhsInboundQueue.sendMessage(largeEhrCore); + + await().atMost(30, TimeUnit.SECONDS) + .untilAsserted(() -> assertTrue(conversationStatusMatches(INBOUND_CONVERSATION_ID, INBOUND_CONTINUE_REQUEST_SENT))); + + await().atMost(30, TimeUnit.SECONDS) + .untilAsserted(() -> assertTrue(conversationStatusMatches(INBOUND_CONVERSATION_ID, INBOUND_TIMEOUT))); + } + + private static String getRepoIncomingMessage() { + final String repoIncomingEvent = """ + { + "conversationId": "%s", + "nhsNumber": "%s", + "nemsMessageId": "%s", + "sourceGp": "%s", + "destinationGp": "%s", + "nemsEventLastUpdated": "%s" + } + """; + + return repoIncomingEvent.formatted( + INBOUND_CONVERSATION_ID.toString().toUpperCase(), + NHS_NUMBER, + NEMS_MESSAGE_ID, + SOURCE_GP, + DESTINATION_GP, + NEMS_EVENT_LAST_UPDATED + ); + } + + private void createStubForGp2GpMessengerEhrRequest() { + final String endpoint = "/health-record-requests/%s".formatted(NHS_NUMBER); + + stubFor(post(urlMatching(endpoint)) + .withHeader("Authorization", equalTo(gp2gpMessengerAuthKey)) + .withHeader("Content-Type", equalTo("application/json")) + .willReturn(aResponse().withStatus(204))); + } + + private void createStubForGp2GpMessengerContinueRequest() { + final String endpoint = "/health-record-requests/continue-message"; + + stubFor(post(urlMatching(endpoint)) + .withHeader("Authorization", equalTo(gp2gpMessengerAuthKey)) + .withHeader("Content-Type", equalTo("application/json")) + .willReturn(aResponse().withStatus(204))); + } + + private void stubFetchStorageUrl(UUID inboundConversationId, UUID messageId) { + final String endpoint = "/messages/%s/%s".formatted( + inboundConversationId.toString().toUpperCase(), + messageId.toString().toUpperCase() + ); + + stubFor(get(urlMatching(endpoint)) + .withHeader("Authorization", equalTo(ehrRepoAuthKey)) + .withHeader("Content-Type", equalTo("application/json")) + .willReturn(aResponse() + // Needs to be a valid URL, parsed into java.net.URL. + .withBody(PRESIGNED_URL) + .withStatus(200))); + } + + private void stubPresignedUrlUploadMessage() { + final String endpoint = "/presigned/url"; + + stubFor(put(urlMatching(endpoint)) + .willReturn(aResponse().withStatus(200))); + } + + private void stubConfirmMessageStored(String healthRecordStatus, int httpResponseStatus) { + final String endpoint = "/messages"; + final String response = """ + { + "healthRecordStatus": "%s" + } + """.formatted(healthRecordStatus); + + stubFor(post(urlMatching(endpoint)) + .withHeader("Authorization", equalTo(ehrRepoAuthKey)) + .withHeader("Content-Type", equalTo("application/json")) + .willReturn(aResponse() + .withBody(response) + .withStatus(httpResponseStatus))); + } + + private boolean conversationStatusMatches(UUID inboundConversationId, ConversationTransferStatus conversationTransferStatus) { + try { + final ConversationRecord foundRecord = transferService.getConversationByInboundConversationId(inboundConversationId); + return ConversationTransferStatus.valueOf(foundRecord.state()).equals(conversationTransferStatus); + } catch (Exception exception) { return false; } + } +} \ No newline at end of file diff --git a/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/utils/MessageParsingUtility.java b/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/utils/MessageParsingUtility.java new file mode 100644 index 000000000..2b9e93129 --- /dev/null +++ b/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/utils/MessageParsingUtility.java @@ -0,0 +1,23 @@ +package uk.nhs.prm.repo.ehrtransferservice.utils; + +import java.util.Optional; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public final class MessageParsingUtility { + private static final String MESSAGE_ID_REGEX = "([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})"; + + private MessageParsingUtility() { } + + public static Optional getMessageId(String message) { + final Pattern pattern = Pattern.compile(MESSAGE_ID_REGEX); + final Matcher matcher = pattern.matcher(message); + + if(matcher.find()) { + return Optional.of(UUID.fromString(matcher.group(1))); + } + + return Optional.empty(); + } +} \ No newline at end of file diff --git a/src/integration/resources/application-test.properties b/src/integration/resources/application-test.properties index 9683c4f0d..c98c82522 100644 --- a/src/integration/resources/application-test.properties +++ b/src/integration/resources/application-test.properties @@ -43,6 +43,6 @@ ehrRepoAuthKey=${EHR_TRANSFER_SERVICE_AUTHORIZATION_KEYS_FOR_EHR_REPO:auth-key-2 gp2gpMessengerUrl=http://localhost:8080 gp2gpMessengerAuthKey=${EHR_TRANSFER_SERVICE_AUTHORIZATION_KEYS_FOR_GP2GP_MESSENGER:auth-key-3} -inboundTimeoutSeconds=300 +inboundTimeoutSeconds=${INBOUND_TIMEOUT_SECONDS:20} spring.main.allow-bean-definition-overriding=true \ No newline at end of file diff --git a/src/test/java/uk/nhs/prm/repo/ehrtransferservice/handlers/LargeMessageFragmentHandlerTest.java b/src/test/java/uk/nhs/prm/repo/ehrtransferservice/handlers/LargeMessageFragmentHandlerTest.java index da01addba..31b1279b9 100644 --- a/src/test/java/uk/nhs/prm/repo/ehrtransferservice/handlers/LargeMessageFragmentHandlerTest.java +++ b/src/test/java/uk/nhs/prm/repo/ehrtransferservice/handlers/LargeMessageFragmentHandlerTest.java @@ -96,8 +96,8 @@ private static StoreMessageResult getStoreMessageResult(Type type) { StoreMessageResponseBody responseBody; switch (type) { - case Type.COMPLETE -> responseBody = new StoreMessageResponseBody("complete"); - case Type.INCOMPLETE -> responseBody = new StoreMessageResponseBody("incomplete"); + case COMPLETE -> responseBody = new StoreMessageResponseBody("complete"); + case INCOMPLETE -> responseBody = new StoreMessageResponseBody("incomplete"); default -> throw new JUnitException("Invalid type provided for getResponseBody(String type)"); } From 6058a927ef68e7cf2efad53e3136ef5d9cbc6b23 Mon Sep 17 00:00:00 2001 From: Mohammad Iqbal Date: Thu, 16 May 2024 16:38:58 +0100 Subject: [PATCH 2/8] [PRMT-4817] - Modified application-test.properties inboundTimeoutSeconds --- .../repo/ehrtransferservice/repo_incoming/EhrRequestTest.java | 1 - src/integration/resources/application-test.properties | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java b/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java index fb574206c..793501808 100644 --- a/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java +++ b/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java @@ -54,7 +54,6 @@ class EhrRequestTest { private static final String NEMS_EVENT_LAST_UPDATED = "2017-11-01T15:00:33+00:00"; private static final String SOURCE_GP = "B14758"; private static final String PRESIGNED_URL = "http://localhost:8080/presigned/url"; - private static final String REPO_INCOMING_MESSAGE = getRepoIncomingMessage(); @Autowired diff --git a/src/integration/resources/application-test.properties b/src/integration/resources/application-test.properties index c98c82522..6eb0547d4 100644 --- a/src/integration/resources/application-test.properties +++ b/src/integration/resources/application-test.properties @@ -43,6 +43,6 @@ ehrRepoAuthKey=${EHR_TRANSFER_SERVICE_AUTHORIZATION_KEYS_FOR_EHR_REPO:auth-key-2 gp2gpMessengerUrl=http://localhost:8080 gp2gpMessengerAuthKey=${EHR_TRANSFER_SERVICE_AUTHORIZATION_KEYS_FOR_GP2GP_MESSENGER:auth-key-3} -inboundTimeoutSeconds=${INBOUND_TIMEOUT_SECONDS:20} +inboundTimeoutSeconds=20 spring.main.allow-bean-definition-overriding=true \ No newline at end of file From e1bf1a384ed166e329941d29c29303cfbe7929a0 Mon Sep 17 00:00:00 2001 From: Mohammad Iqbal Date: Thu, 16 May 2024 17:00:09 +0100 Subject: [PATCH 3/8] [PRMT-4817] - Updated README.md with WireMock documentation --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index f9ddced5c..1fff96384 100644 --- a/README.md +++ b/README.md @@ -153,3 +153,10 @@ Please follow this design to ensure the ssm keys are easy to maintain and naviga | -------------------| ----------------------------------------| ------------------------------------------------------| | **User-specified** |`/repo/?/user-input/` | `/repo/${var.environment}/user-input/db-username` | | **Auto-generated** |`/repo/?/output//`| `/repo/output/prm-deductions-base-infra/root-zone-id` | + +## WireMock for Integration Testing + +Integration tests that utilise WireMock will need to configure their endpoints so that they point to localhost. + +WireMock is configured within tests by using `@WireMockTest(httpPort = 8080)` at class level where `8080` can be configured +to any port of your choice. When stubbing, we need to ensure that the URL is `http://localhost:{PORT DEFINED ABOVE}`. \ No newline at end of file From 10521dfb13ffeadd014dbe1212ce542828ec77cd Mon Sep 17 00:00:00 2001 From: Mohammad Iqbal Date: Fri, 17 May 2024 11:19:43 +0100 Subject: [PATCH 4/8] [PRMT-4817] - Assertion for activity status to be no longer active --- .../repo/ehrtransferservice/repo_incoming/EhrRequestTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java b/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java index 793501808..eb8837f2b 100644 --- a/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java +++ b/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java @@ -80,7 +80,6 @@ class EhrRequestTest { @AfterEach void afterEach() { sqsQueueUtility.purgeQueue(repoIncomingQueueName); - transferService.updateConversationTransferStatus(INBOUND_CONVERSATION_ID, INBOUND_COMPLETE); transferTrackerDbUtility.deleteItem(INBOUND_CONVERSATION_ID, CONVERSATION); } From f2fdf00bddc1ce0bf94aa785560fc2f0949de9b0 Mon Sep 17 00:00:00 2001 From: Mohammad Iqbal Date: Fri, 17 May 2024 11:23:52 +0100 Subject: [PATCH 5/8] [PRMT-4817] - Updated README.md for Wiremock documentation --- README.md | 42 +++++++++++++++++-- .../repo_incoming/EhrRequestTest.java | 12 ++++++ 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1fff96384..b01b1a3e6 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,43 @@ Please follow this design to ensure the ssm keys are easy to maintain and naviga ## WireMock for Integration Testing -Integration tests that utilise WireMock will need to configure their endpoints so that they point to localhost. +When using WireMock for integration testing, it is essential to configure your endpoints to point to `localhost`. -WireMock is configured within tests by using `@WireMockTest(httpPort = 8080)` at class level where `8080` can be configured -to any port of your choice. When stubbing, we need to ensure that the URL is `http://localhost:{PORT DEFINED ABOVE}`. \ No newline at end of file +### Configuration + +To set up WireMock within your tests, use the `@WireMockTest(httpPort = 8080)` annotation at the class level. The port number `8080` is configurable and can be replaced with any port of your choice. This annotation ensures that WireMock is active on the specified port during the test execution. + +### Stubbing + +When stubbing responses with WireMock, you must ensure that the URL used in the stubs matches the local server configuration. Specifically, the URL should be in the format `http://localhost:{PORT}` where `{PORT}` corresponds to the port number defined in the `@WireMockTest` annotation. + +### Example + +Here is an example of a test class using WireMock: + +```java +import com.github.tomakehurst.wiremock.junit5.WireMockTest; +import static com.github.tomakehurst.wiremock.client.WireMock.*; + +@WireMockTest(httpPort = 8080) +public class MyIntegrationTest { + + @Test + public void testEndpoint() { + stubFor(get(urlEqualTo("/some-endpoint")) + .willReturn(aResponse() + .withStatus(200) + .withBody("Hello, WireMock!"))); + + // Your test code here, e.g., making an HTTP request to http://localhost:8080/some-endpoint + } +} +``` + +In this example: + +* The @WireMockTest(httpPort = 8080) annotation configures WireMock to run on port 8080. +* The stubFor method is used to define a stub for the endpoint /some-endpoint, returning a 200 OK response with the body "Hello, WireMock!". +* Your test logic would involve making an HTTP request to http://localhost:8080/some-endpoint to verify the stubbed response. + +By following this approach, you can effectively use WireMock to simulate and test interactions with external services in your integration tests. \ No newline at end of file diff --git a/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java b/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java index eb8837f2b..29a1c9cda 100644 --- a/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java +++ b/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java @@ -4,9 +4,11 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -16,6 +18,7 @@ import uk.nhs.prm.repo.ehrtransferservice.database.TransferService; import uk.nhs.prm.repo.ehrtransferservice.database.enumeration.ConversationTransferStatus; import uk.nhs.prm.repo.ehrtransferservice.database.model.ConversationRecord; +import uk.nhs.prm.repo.ehrtransferservice.services.ConversationActivityService; import uk.nhs.prm.repo.ehrtransferservice.utils.SqsQueueUtility; import uk.nhs.prm.repo.ehrtransferservice.utils.TransferTrackerDbUtility; @@ -31,6 +34,7 @@ import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; import static org.awaitility.Awaitility.await; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static uk.nhs.prm.repo.ehrtransferservice.database.enumeration.ConversationTransferStatus.INBOUND_COMPLETE; import static uk.nhs.prm.repo.ehrtransferservice.database.enumeration.ConversationTransferStatus.INBOUND_CONTINUE_REQUEST_SENT; @@ -45,6 +49,7 @@ @ActiveProfiles("test") @WireMockTest(httpPort = 8080) @ExtendWith(SpringExtension.class) +@ExtendWith(MockitoExtension.class) @ExtendWith(ForceXercesParserExtension.class) @ContextConfiguration(classes = LocalStackAwsConfig.class) class EhrRequestTest { @@ -65,6 +70,9 @@ class EhrRequestTest { @Autowired private SqsQueueUtility sqsQueueUtility; + @SpyBean + private ConversationActivityService activityService; + @Value("${aws.repoIncomingQueueName}") private String repoIncomingQueueName; @@ -92,6 +100,10 @@ void Given_ValidRepoIncomingEvent_When_PublishedToRepoIncomingQueue_Then_CreateC // then await().atMost(30, TimeUnit.SECONDS) .untilAsserted(() -> assertTrue(conversationStatusMatches(INBOUND_CONVERSATION_ID, INBOUND_REQUEST_SENT))); + + // The following is to stop the activity from interfering with tests run afterwards + transferService.updateConversationTransferStatus(INBOUND_CONVERSATION_ID, INBOUND_COMPLETE); + assertFalse(activityService.isConversationActive(INBOUND_CONVERSATION_ID)); } @Test From d869804302a9e47ea0e0bbbca918e2d09c0dd033 Mon Sep 17 00:00:00 2001 From: Mohammad Iqbal Date: Fri, 17 May 2024 11:47:30 +0100 Subject: [PATCH 6/8] [PRMT-4817] - Updated name of integration test --- .../repo/ehrtransferservice/repo_incoming/EhrRequestTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java b/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java index 29a1c9cda..fbc081f57 100644 --- a/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java +++ b/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java @@ -92,7 +92,7 @@ void afterEach() { } @Test - void Given_ValidRepoIncomingEvent_When_PublishedToRepoIncomingQueue_Then_CreateConversationAndUpdateStatusToInboundRequestSent() { + void Given_ValidRepoIncomingEvent_When_PublishedToRepoIncomingQueue_Then_CreateConversationAndUpdateStatusToInboundRequestSentAndCheckInMemoryConversationIsInactive() { // when createStubForGp2GpMessengerEhrRequest(); sqsQueueUtility.sendSqsMessage(REPO_INCOMING_MESSAGE, repoIncomingQueueName); From 0af5c3cc350fb3ebccb3a415c915da8859dc51fc Mon Sep 17 00:00:00 2001 From: Mohammad Iqbal Date: Fri, 17 May 2024 14:39:16 +0100 Subject: [PATCH 7/8] [PRMT-4817] - Verify conversation is inactive afterEach test --- .../ehrtransferservice/repo_incoming/EhrRequestTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java b/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java index fbc081f57..e903b6c6d 100644 --- a/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java +++ b/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java @@ -89,10 +89,11 @@ class EhrRequestTest { void afterEach() { sqsQueueUtility.purgeQueue(repoIncomingQueueName); transferTrackerDbUtility.deleteItem(INBOUND_CONVERSATION_ID, CONVERSATION); + assertFalse(activityService.isConversationActive(INBOUND_CONVERSATION_ID)); } @Test - void Given_ValidRepoIncomingEvent_When_PublishedToRepoIncomingQueue_Then_CreateConversationAndUpdateStatusToInboundRequestSentAndCheckInMemoryConversationIsInactive() { + void Given_ValidRepoIncomingEvent_When_PublishedToRepoIncomingQueue_Then_CreateConversationAndUpdateStatusToInboundRequestSentAndCheckInMemoryConversationIsActive() { // when createStubForGp2GpMessengerEhrRequest(); sqsQueueUtility.sendSqsMessage(REPO_INCOMING_MESSAGE, repoIncomingQueueName); @@ -101,9 +102,10 @@ void Given_ValidRepoIncomingEvent_When_PublishedToRepoIncomingQueue_Then_CreateC await().atMost(30, TimeUnit.SECONDS) .untilAsserted(() -> assertTrue(conversationStatusMatches(INBOUND_CONVERSATION_ID, INBOUND_REQUEST_SENT))); + assertTrue(activityService.isConversationActive(INBOUND_CONVERSATION_ID)); + // The following is to stop the activity from interfering with tests run afterwards transferService.updateConversationTransferStatus(INBOUND_CONVERSATION_ID, INBOUND_COMPLETE); - assertFalse(activityService.isConversationActive(INBOUND_CONVERSATION_ID)); } @Test From 1468adae832a870621aa8c4af605152373a0e443 Mon Sep 17 00:00:00 2001 From: Mohammad Iqbal Date: Fri, 17 May 2024 16:25:03 +0100 Subject: [PATCH 8/8] [PRMT-4817] - Replaced @SpyBean with @AutoWired for activityService within EhrRequestTest.java --- .../repo/ehrtransferservice/repo_incoming/EhrRequestTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java b/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java index e903b6c6d..c22757c17 100644 --- a/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java +++ b/src/integration/java/uk/nhs/prm/repo/ehrtransferservice/repo_incoming/EhrRequestTest.java @@ -70,7 +70,7 @@ class EhrRequestTest { @Autowired private SqsQueueUtility sqsQueueUtility; - @SpyBean + @Autowired private ConversationActivityService activityService; @Value("${aws.repoIncomingQueueName}")