Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* The GP2GP Adaptor now adds the EhrComposition / confidentialityCode field when Encounter.meta.security contains NOPAT security entry
* The GP2GP Adaptor now populates the ObservationStatement / confidentialityCode field when the .meta.security field of an Uncategorized Data Observation contains NOPAT
* When List.meta.security field contains NOPAT, the GP2GP Adaptor will now populate the CompoundStatement.confidentialityCode
* The GP2GP Adaptor now throws an exception when the Access Structure Record is empty, thereby rejecting the transfer

### Fixed
* When DiagnosticReport doesn't contain a Specimen reference, instead of "DUMMY" "NOT-PRESENT" value is used
Expand Down
6 changes: 3 additions & 3 deletions docker/run-e2e-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

set -e

if [ -f "vars.sh" ]; then
source vars.sh
if [ -f "vars.local.e2e.sh" ]; then
source vars.local.e2e.sh
else
echo "No vars.sh defined. Using docker-compose defaults."
echo "No vars.local.e2e.sh defined. Using docker-compose defaults."
fi
if [[ "$(docker network ls | grep "commonforgp2gp")" == "" ]] ; then
docker network create commonforgp2gp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class EhrExtractTest {
private static final String NHS_NUMBER_RESPONSE_MISSING_PATIENT_RESOURCE = "2906543841";
private static final String NHS_NUMBER_MEDICUS_BASED_ON = "9302014592";
private static final String NHS_NUMBER_INVALID_CONTENT_TYPE_DOC = "9817280691";
private static final String NHS_NUMBER_NO_CLINICAL_CONTENT_STRUCTURE = "9736435687";
private static final String NHS_NUMBER_BODY_SITE = "1239577290";
private static final String EHR_EXTRACT_REQUEST_TEST_FILE = "/ehrExtractRequest.json";
private static final String EHR_EXTRACT_REQUEST_WITHOUT_NHS_NUMBER_TEST_FILE = "/ehrExtractRequestWithoutNhsNumber.json";
Expand Down Expand Up @@ -442,6 +443,30 @@ void When_ExtractRequestReceivedForMedicusPatientWithBasedOn_Expect_ExtractStatu

}

@Test
void When_ExtractRequestReceivedForPatientWithoutClinicalContent_Expect_ExtractStatusAndDocumentDataAddedToDbAndReturnCode10() throws Exception {
String conversationId = UUID.randomUUID().toString();
String ehrExtractRequest = buildEhrExtractRequest(conversationId, NHS_NUMBER_NO_CLINICAL_CONTENT_STRUCTURE, FROM_ODS_CODE_1);
MessageQueue.sendToMhsInboundQueue(ehrExtractRequest);

var requestJournal = waitFor(() -> {
try {
return mhsMockRequestsJournal.getRequestsJournal(conversationId);
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
}
});

assertThat(requestJournal).hasSize(1);

var ehrExtractStatus = waitFor(() -> Mongo.findEhrExtractStatus(conversationId));
assertThatInitialRecordWasCreated(conversationId, ehrExtractStatus, NHS_NUMBER_NO_CLINICAL_CONTENT_STRUCTURE, FROM_ODS_CODE_1);

var error = (Document) ehrExtractStatus.get("error");
assertThat(error).isNotEmpty();
softly.assertThat(error.get("code")).isEqualTo(NACK_CODE_FAILED_TO_GENERATE_EHR);
}

@Test
void When_ExtractRequestReceivedForEMISPWTP2_Expect_ExtractStatusAndDocumentDataAddedToDatabase() throws IOException, NamingException, JMSException {
String conversationId = UUID.randomUUID().toString();
Expand Down
6 changes: 3 additions & 3 deletions service/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,13 @@ dependencies {
testImplementation 'org.wiremock:wiremock-standalone:3.13.1'
testImplementation 'com.squareup.okhttp3:okhttp:5.1.0'
testImplementation 'com.squareup.okhttp3:mockwebserver3:5.1.0'
testImplementation 'com.adobe.testing:s3mock-testcontainers:4.9.1'
testImplementation 'com.adobe.testing:s3mock-testcontainers:4.7.0'

spotbugs 'com.github.spotbugs:spotbugs:4.9.6'
spotbugs 'com.github.spotbugs:spotbugs-annotations:4.9.6'

pitest 'com.arcmutate:base:1.3.2'
pitest 'com.arcmutate:pitest-git-plugin:2.2.4'
pitest 'com.arcmutate:pitest-git-plugin:2.1.0'
}

test {
Expand Down Expand Up @@ -165,7 +165,7 @@ spotbugsMain {
}

pitest {
pitestVersion = '1.16.1'
pitestVersion = '1.16.3'
junit5PluginVersion = '1.2.1'
outputFormats = ['gitci']

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
@ExtendWith({SpringExtension.class, MongoDBExtension.class, ActiveMQExtension.class, MockitoExtension.class})
@SpringBootTest
@DirtiesContext
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
public class SendEhrExtractCoreComponentTest extends BaseTaskTest {
private static final String OUTBOUND_MESSAGE = serializeOutboundMessage("payload");
public static final String OUTBOUND_MESSAGE_WITH_PLACEHOLDER =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static ActiveMqContainer getInstance() {
@Override
public void start() {
super.start();
var containerBrokerUri = "amqp://" + getContainerIpAddress() + ":" + getMappedPort(ACTIVEMQ_PORT);
var containerBrokerUri = "amqp://" + getHost() + ":" + getMappedPort(ACTIVEMQ_PORT);
System.setProperty("GP2GP_AMQP_BROKERS", containerBrokerUri);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import uk.nhs.adaptors.gp2gp.ehr.SendAcknowledgementTaskDefinition;
import uk.nhs.adaptors.gp2gp.ehr.exception.EhrExtractException;
import uk.nhs.adaptors.gp2gp.ehr.exception.EhrMapperException;
import uk.nhs.adaptors.gp2gp.ehr.exception.EhrValidationException;
import uk.nhs.adaptors.gp2gp.gpc.exception.EhrRequestException;
import uk.nhs.adaptors.gp2gp.gpc.exception.GpConnectException;
import uk.nhs.adaptors.gp2gp.gpc.exception.GpConnectInvalidException;
Expand All @@ -30,6 +31,7 @@ public class TaskErrorHandler {
EhrRequestException.class, this::handleRequestError,
EhrExtractException.class, this::handleTranslationError,
EhrMapperException.class, this::handleTranslationError,
EhrValidationException.class, this::handleTranslationError,
FhirValidationException.class, this::handleTranslationError,
GpConnectException.class, this::handleGpConnectError,
GpConnectInvalidException.class, this::handleInvalidNotAuthError,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package uk.nhs.adaptors.gp2gp.ehr.exception;

public class EhrValidationException extends RuntimeException {

public EhrValidationException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import uk.nhs.adaptors.gp2gp.ehr.utils.TemplateUtils;
import uk.nhs.adaptors.gp2gp.gpc.GetGpcStructuredTaskDefinition;

import uk.nhs.adaptors.gp2gp.ehr.exception.EhrValidationException;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -56,6 +58,12 @@ public EhrExtractTemplateParameters mapBundleToEhrFhirExtractParams(
mappedComponents.addAll(nonConsultationResourceMapper.mapRemainingResourcesToEhrCompositions(bundle));
ehrExtractTemplateParameters.setComponents(mappedComponents);

if (mappedComponents.isEmpty()) {
final String message = "could not extract EHR Extract: empty structured access record.";
LOGGER.error(message);
throw new EhrValidationException(message);
}

ehrExtractTemplateParameters.setAgentDirectory(
agentDirectoryMapper.mapEHRFolderToAgentDirectory(bundle, getPatientNhsNumber(getGpcStructuredTaskDefinition))
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import uk.nhs.adaptors.gp2gp.common.service.ProcessFailureHandlingService;
import uk.nhs.adaptors.gp2gp.ehr.exception.EhrExtractException;
import uk.nhs.adaptors.gp2gp.ehr.exception.EhrMapperException;
import uk.nhs.adaptors.gp2gp.ehr.exception.EhrValidationException;
import uk.nhs.adaptors.gp2gp.gpc.exception.EhrRequestException;
import uk.nhs.adaptors.gp2gp.gpc.exception.GpConnectException;
import uk.nhs.adaptors.gp2gp.gpc.exception.GpConnectInvalidException;
Expand Down Expand Up @@ -65,6 +66,17 @@ void When_HandleProcessingError_WithEhrRequestException_Expect_ProcessToBeFailed
any());
}

@Test
void When_HandleProcessingError_WithEhrValidationException_Expect_ProcessToBeFailedWithCorrectCode() {
taskErrorHandler.handleProcessingError(new EhrValidationException(TEST_EXCEPTION_MESSAGE), taskDefinition);

verify(processFailureHandlingService).failProcess(
any(),
eq("10"),
eq("Failed to successfully generate EHR Extract."),
any());
}

@Test
void When_HandleProcessingError_WithEhrRequestException_Expect_ReturnValueOfFailService() {
when(processFailureHandlingService.failProcess(any(), any(), any(), any()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.mock;


import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.Collections;

import org.hl7.fhir.dstu3.model.Bundle;
import org.junit.jupiter.api.Test;
Expand All @@ -19,6 +23,7 @@

import uk.nhs.adaptors.gp2gp.common.service.RandomIdGeneratorService;
import uk.nhs.adaptors.gp2gp.common.service.TimestampService;
import uk.nhs.adaptors.gp2gp.ehr.exception.EhrValidationException;
import uk.nhs.adaptors.gp2gp.gpc.GetGpcStructuredTaskDefinition;

@ExtendWith(MockitoExtension.class)
Expand Down Expand Up @@ -50,6 +55,8 @@ class EhrExtractMapperTest {

@Test
void When_NhsOverrideNumberProvided_Expect_OverrideToBeUsed() {
when(nonConsultationResourceMapper.mapRemainingResourcesToEhrCompositions(any()))
.thenReturn(Arrays.asList("not", "empty"));
ReflectionTestUtils.setField(ehrExtractMapper, OVERRIDE_NHS_NUMBER, OVERRIDE_NHS_NUMBER_VALUE);
when(agentDirectoryMapper.mapEHRFolderToAgentDirectory(any(Bundle.class), eq(OVERRIDE_NHS_NUMBER_VALUE)))
.thenReturn(OVERRIDE_NHS_NUMBER_VALUE);
Expand All @@ -66,6 +73,8 @@ void When_NhsOverrideNumberProvided_Expect_OverrideToBeUsed() {

@Test
void When_NhsOverrideNumberIsBlank_Expect_ActualNhsNumberIsUsed() {
when(nonConsultationResourceMapper.mapRemainingResourcesToEhrCompositions(any()))
.thenReturn(Arrays.asList("not", "empty"));
when(agentDirectoryMapper.mapEHRFolderToAgentDirectory(any(Bundle.class), eq(NHS_NUMBER)))
.thenReturn(NHS_NUMBER);
when(timestampService.now()).thenReturn(Instant.now().truncatedTo(ChronoUnit.MILLIS));
Expand All @@ -79,6 +88,27 @@ void When_NhsOverrideNumberIsBlank_Expect_ActualNhsNumberIsUsed() {
assertThat(parameters.getAgentDirectory()).isEqualTo(NHS_NUMBER);
}

@Test
void When_BundleHasNoMappableContent_Expect_EhrValidationExceptionIsThrown() {
when(timestampService.now()).thenReturn(Instant.now().truncatedTo(ChronoUnit.MILLIS));

var taskDef = GetGpcStructuredTaskDefinition.builder()
.nhsNumber(NHS_NUMBER)
.build();
var bundle = mock(Bundle.class);

when(nonConsultationResourceMapper.mapRemainingResourcesToEhrCompositions(any(Bundle.class)))
.thenReturn(Collections.emptyList());

EhrValidationException thrown = assertThrows(EhrValidationException.class, () ->
ehrExtractMapper.mapBundleToEhrFhirExtractParams(taskDef, bundle)
);

assertThat(thrown.getMessage()).isEqualTo("could not extract EHR Extract: empty structured access record.");
}



@Test
void When_BuildEhrCompositionForSkeletonEhrExtract_Expect_ExpectedComponentBuilt() {
var documentId = "documentId";
Expand Down
Loading