Skip to content

Commit cf0dad6

Browse files
authored
NIAD-3144 - Send over {Lab Results}.meta.security NOPAT field to incumbent (#828)
* [NIAD-3144] Create TestUtility.java and create method to parse a given JSON file into a FHIR resource * [NIAD-3144] Update TestUtility.java and update DiagnosticReportMapperTest.java, added two boilerplate tests * [NIAD-3144] Add failing unit test * [NIAD-3144] Update tests to support confidentialityService, added failing unit tests * [NIAD-3144] Add more utility methods to TestUtility.java * [NIAD-3144] Add and remove test resources * [NIAD-3144] Update production code for DiagnosticReportMapper * [NIAD-3144] Improve test assertions * [NIAD-3144] Checkstyle violations fixed, enhance SpecimenMapperTest.java * [NIAD-3144] Add failing unit test * [NIAD-3144] Add logic to production code to for confidentialityCode support of specimens * [NIAD-3144] Test refactors * [NIAD-3144] TestUtility refactors * [NIAD-3144] Add test coverage to SpecimenMapperTest.java * [NIAD-3144] Refactor code to abide to single responsibility principle * [NIAD-3144] Address failing unit test * [NIAD-3144] Address failing unit test
1 parent c462462 commit cf0dad6

16 files changed

+421
-112
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010

1111
* When mapping `AllergyIntolerances` which contain a `NOPAT` `meta.security` tag the resultant XML for that resource
1212
will contain a `NOPAT` `confidentialityCode` element.
13+
* When mapping a `DiagnosticReport` or `Specimen` which contains a `NOPAT` `meta.security` tag the resultant XML for that resource
14+
will contain a `NOPAT` `confidentialityCode` element.
1315

1416
## [2.0.6] - 2024-07-29
1517

service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/mapper/diagnosticreport/DiagnosticReportMapper.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.springframework.beans.factory.annotation.Autowired;
3232
import org.springframework.stereotype.Component;
3333

34+
import uk.nhs.adaptors.gp2gp.common.service.ConfidentialityService;
3435
import uk.nhs.adaptors.gp2gp.common.service.RandomIdGeneratorService;
3536
import uk.nhs.adaptors.gp2gp.ehr.mapper.CommentType;
3637
import uk.nhs.adaptors.gp2gp.ehr.mapper.IdMapper;
@@ -69,6 +70,7 @@ public class DiagnosticReportMapper {
6970
private final SpecimenMapper specimenMapper;
7071
private final ParticipantMapper participantMapper;
7172
private final RandomIdGeneratorService randomIdGeneratorService;
73+
private final ConfidentialityService confidentialityService;
7274

7375
public String mapDiagnosticReportToCompoundStatement(DiagnosticReport diagnosticReport) {
7476
List<Specimen> specimens = fetchSpecimens(diagnosticReport);
@@ -87,7 +89,8 @@ public String mapDiagnosticReportToCompoundStatement(DiagnosticReport diagnostic
8789
.extensionId(fetchExtensionId(diagnosticReport.getIdentifier()))
8890
.availabilityTimeElement(StatementTimeMappingUtils.prepareAvailabilityTime(diagnosticReport.getIssuedElement()))
8991
.narrativeStatements(reportLevelNarrativeStatements)
90-
.specimens(mappedSpecimens);
92+
.specimens(mappedSpecimens)
93+
.confidentialityCode(confidentialityService.generateConfidentialityCode(diagnosticReport).orElse(null));
9194

9295
if (diagnosticReport.hasPerformer() && diagnosticReport.getPerformerFirstRep().hasActor()) {
9396
final String participantReference = messageContext.getAgentDirectory().getAgentId(

service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/mapper/diagnosticreport/SpecimenMapper.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.springframework.beans.factory.annotation.Autowired;
2929
import org.springframework.stereotype.Component;
3030

31+
import uk.nhs.adaptors.gp2gp.common.service.ConfidentialityService;
3132
import uk.nhs.adaptors.gp2gp.common.service.RandomIdGeneratorService;
3233
import uk.nhs.adaptors.gp2gp.ehr.mapper.CommentType;
3334
import uk.nhs.adaptors.gp2gp.ehr.mapper.MessageContext;
@@ -61,6 +62,7 @@ public class SpecimenMapper {
6162
private final MessageContext messageContext;
6263
private final ObservationMapper observationMapper;
6364
private final RandomIdGeneratorService randomIdGeneratorService;
65+
private final ConfidentialityService confidentialityService;
6466

6567
public String mapSpecimenToCompoundStatement(Specimen specimen, List<Observation> observations, DiagnosticReport diagnosticReport) {
6668
String availabilityTimeElement = StatementTimeMappingUtils.prepareAvailabilityTime(diagnosticReport.getIssuedElement());
@@ -71,7 +73,8 @@ public String mapSpecimenToCompoundStatement(Specimen specimen, List<Observation
7173
.availabilityTimeElement(availabilityTimeElement)
7274
.specimenRoleId(randomIdGeneratorService.createNewId())
7375
.narrativeStatementId(randomIdGeneratorService.createNewId())
74-
.observations(mappedObservations);
76+
.observations(mappedObservations)
77+
.confidentialityCode(confidentialityService.generateConfidentialityCode(specimen).orElse(null));
7578

7679
buildAccessionIdentifier(specimen).ifPresent(specimenCompoundStatementTemplateParameters::accessionIdentifier);
7780
buildEffectiveTimeForSpecimen(specimen).ifPresent(specimenCompoundStatementTemplateParameters::effectiveTime);
@@ -151,7 +154,7 @@ private String mapObservationsAssociatedWithSpecimen(Specimen specimen, List<Obs
151154

152155
private boolean dummySpecimenOrObservationExists(Specimen specimen, List<Observation> observations) {
153156
return specimen.getIdElement().getIdPart().contains(DUMMY_SPECIMEN_ID_PREFIX)
154-
|| (!observations.isEmpty() && observations.get(0).getIdElement().getIdPart().contains(DUMMY_OBSERVATION_ID_PREFIX));
157+
|| (!observations.isEmpty() && observations.getFirst().getIdElement().getIdPart().contains(DUMMY_OBSERVATION_ID_PREFIX));
155158
}
156159

157160
private Optional<String> buildSpecimenNarrativeStatement(Specimen specimen, String availabilityTimeElement,

service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/mapper/parameters/diagnosticreport/DiagnosticReportCompoundStatementTemplateParameters.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ public class DiagnosticReportCompoundStatementTemplateParameters {
1414
private String narrativeStatements;
1515
private String specimens;
1616
private String participant;
17+
private String confidentialityCode;
1718
}

service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/mapper/parameters/diagnosticreport/SpecimenCompoundStatementTemplateParameters.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ public class SpecimenCompoundStatementTemplateParameters {
1818
private String narrativeStatementId;
1919
private String participant;
2020
private String observations;
21+
private String confidentialityCode;
2122
}

service/src/main/resources/templates/diagnostic_report_compound_statement_template.mustache

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
<center nullFlavor="NI"/>
1313
</effectiveTime>
1414
{{{availabilityTimeElement}}}
15+
{{#confidentialityCode}}
16+
{{{confidentialityCode}}}
17+
{{/confidentialityCode}}
1518
{{#narrativeStatements}}
1619
{{{.}}}
1720
{{/narrativeStatements}}

service/src/main/resources/templates/specimen_compound_statement_template.mustache

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
<center nullFlavor="NI"/>
88
</effectiveTime>
99
{{{availabilityTimeElement}}}
10+
{{#confidentialityCode}}
11+
{{{confidentialityCode}}}
12+
{{/confidentialityCode}}
1013
<specimen typeCode="SPC">
1114
<specimenRole classCode="SPEC">
1215
<id root="{{specimenRoleId}}"/>

service/src/test/java/uk/nhs/adaptors/gp2gp/ehr/mapper/EhrExtractMapperComponentTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,8 @@ public void setUp() {
153153
ObservationMapper specimenObservationMapper = new ObservationMapper(
154154
messageContext, structuredObservationValueMapper, codeableConceptCdMapper,
155155
participantMapper, multiStatementObservationHolderFactory);
156-
SpecimenMapper specimenMapper = new SpecimenMapper(messageContext, specimenObservationMapper, randomIdGeneratorService);
156+
SpecimenMapper specimenMapper = new SpecimenMapper(messageContext, specimenObservationMapper,
157+
randomIdGeneratorService, confidentialityService);
157158
DocumentReferenceToNarrativeStatementMapper documentReferenceToNarrativeStatementMapper
158159
= new DocumentReferenceToNarrativeStatementMapper(
159160
messageContext, new SupportedContentTypes(), timestampService, participantMapper);
@@ -180,7 +181,7 @@ codeableConceptCdMapper, new ParticipantMapper()),
180181
),
181182
new RequestStatementMapper(messageContext, codeableConceptCdMapper, participantMapper),
182183
new DiagnosticReportMapper(
183-
messageContext, specimenMapper, participantMapper, randomIdGeneratorService
184+
messageContext, specimenMapper, participantMapper, randomIdGeneratorService, confidentialityService
184185
),
185186
new BloodPressureValidator(),
186187
codeableConceptCdMapper

service/src/test/java/uk/nhs/adaptors/gp2gp/ehr/mapper/EncounterComponentsMapperTest.java

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.hl7.fhir.dstu3.model.IdType;
2020
import org.hl7.fhir.dstu3.model.Reference;
2121
import org.hl7.fhir.dstu3.model.ResourceType;
22+
import org.jetbrains.annotations.NotNull;
2223
import org.junit.jupiter.api.AfterEach;
2324
import org.junit.jupiter.api.BeforeEach;
2425
import org.junit.jupiter.api.Test;
@@ -154,12 +155,7 @@ public void setUp() {
154155
= new MedicationStatementMapper(messageContext, codeableConceptCdMapper, participantMapper, randomIdGeneratorService);
155156
ObservationToNarrativeStatementMapper observationToNarrativeStatementMapper =
156157
new ObservationToNarrativeStatementMapper(messageContext, participantMapper);
157-
MultiStatementObservationHolderFactory multiStatementObservationHolderFactory =
158-
new MultiStatementObservationHolderFactory(messageContext, randomIdGeneratorService);
159-
ObservationMapper specimenObservationMapper = new ObservationMapper(
160-
messageContext, structuredObservationValueMapper, codeableConceptCdMapper, participantMapper,
161-
multiStatementObservationHolderFactory);
162-
SpecimenMapper specimenMapper = new SpecimenMapper(messageContext, specimenObservationMapper, randomIdGeneratorService);
158+
SpecimenMapper specimenMapper = getSpecimenMapper(structuredObservationValueMapper, participantMapper);
163159

164160
ObservationStatementMapper observationStatementMapper = new ObservationStatementMapper(
165161
messageContext,
@@ -172,7 +168,7 @@ public void setUp() {
172168
RequestStatementMapper requestStatementMapper
173169
= new RequestStatementMapper(messageContext, codeableConceptCdMapper, participantMapper);
174170
DiagnosticReportMapper diagnosticReportMapper = new DiagnosticReportMapper(
175-
messageContext, specimenMapper, participantMapper, randomIdGeneratorService
171+
messageContext, specimenMapper, participantMapper, randomIdGeneratorService, confidentialityService
176172
);
177173

178174
encounterComponentsMapper = new EncounterComponentsMapper(
@@ -193,6 +189,16 @@ public void setUp() {
193189
);
194190
}
195191

192+
private @NotNull SpecimenMapper getSpecimenMapper(StructuredObservationValueMapper structuredObservationValueMapper,
193+
ParticipantMapper participantMapper) {
194+
MultiStatementObservationHolderFactory multiStatementObservationHolderFactory =
195+
new MultiStatementObservationHolderFactory(messageContext, randomIdGeneratorService);
196+
ObservationMapper specimenObservationMapper = new ObservationMapper(
197+
messageContext, structuredObservationValueMapper, codeableConceptCdMapper, participantMapper,
198+
multiStatementObservationHolderFactory);
199+
return new SpecimenMapper(messageContext, specimenObservationMapper, randomIdGeneratorService, confidentialityService);
200+
}
201+
196202
@AfterEach
197203
public void tearDown() {
198204
messageContext.resetMessageContext();

service/src/test/java/uk/nhs/adaptors/gp2gp/ehr/mapper/diagnosticreport/DiagnosticReportMapperTest.java

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package uk.nhs.adaptors.gp2gp.ehr.mapper.diagnosticreport;
22

33
import static org.assertj.core.api.Assertions.assertThat;
4+
import static org.junit.jupiter.api.Assertions.assertAll;
45
import static org.mockito.ArgumentMatchers.any;
56
import static org.mockito.Mockito.when;
67

78
import java.io.IOException;
9+
import java.util.Optional;
810
import java.util.stream.Stream;
911

1012
import org.hl7.fhir.dstu3.model.Bundle;
@@ -14,6 +16,7 @@
1416
import org.hl7.fhir.dstu3.model.Reference;
1517
import org.hl7.fhir.dstu3.model.ResourceType;
1618
import org.hl7.fhir.dstu3.model.Specimen;
19+
import org.junit.jupiter.api.Test;
1720
import org.junit.jupiter.api.AfterEach;
1821
import org.junit.jupiter.api.BeforeEach;
1922
import org.junit.jupiter.api.extension.ExtendWith;
@@ -26,6 +29,9 @@
2629
import org.mockito.quality.Strictness;
2730
import org.mockito.stubbing.Answer;
2831

32+
import uk.nhs.adaptors.gp2gp.utils.ConfidentialityCodeUtility;
33+
import uk.nhs.adaptors.gp2gp.utils.FileParsingUtility;
34+
import uk.nhs.adaptors.gp2gp.common.service.ConfidentialityService;
2935
import uk.nhs.adaptors.gp2gp.common.service.FhirParseService;
3036
import uk.nhs.adaptors.gp2gp.common.service.RandomIdGeneratorService;
3137
import uk.nhs.adaptors.gp2gp.ehr.mapper.AgentDirectory;
@@ -41,7 +47,7 @@
4147

4248
@ExtendWith(MockitoExtension.class)
4349
@MockitoSettings(strictness = Strictness.LENIENT)
44-
public class DiagnosticReportMapperTest {
50+
class DiagnosticReportMapperTest {
4551
private static final String TEST_FILE_DIRECTORY = "/ehr/mapper/diagnosticreport/";
4652

4753
private static final String INPUT_JSON_BUNDLE = "fhir_bundle.json";
@@ -74,13 +80,17 @@ public class DiagnosticReportMapperTest {
7480
private static final String OUTPUT_XML_EXTENSION_ID = "diagnostic-report-with-extension-id.xml";
7581
private static final String OUTPUT_XML_MULTIPLE_RESULTS = "diagnostic-report-with-multiple-results.xml";
7682

83+
private static final String NOPAT_CONFIDENTIALITY_CODE = ConfidentialityCodeUtility.getNopatHl7v3ConfidentialityCode();
84+
7785
@Mock
7886
private CodeableConceptCdMapper codeableConceptCdMapper;
7987
@Mock
8088
private SpecimenMapper specimenMapper;
8189
@Mock
8290
private MessageContext messageContext;
8391
@Mock
92+
private ConfidentialityService confidentialityService;
93+
@Mock
8494
private IdMapper idMapper;
8595
@Mock
8696
private AgentDirectory agentDirectory;
@@ -108,7 +118,8 @@ public void setUp() throws IOException {
108118

109119
when(randomIdGeneratorService.createNewId()).thenReturn(TEST_ID);
110120

111-
mapper = new DiagnosticReportMapper(messageContext, specimenMapper, new ParticipantMapper(), randomIdGeneratorService);
121+
mapper = new DiagnosticReportMapper(
122+
messageContext, specimenMapper, new ParticipantMapper(), randomIdGeneratorService, confidentialityService);
112123
}
113124

114125
@AfterEach
@@ -118,15 +129,52 @@ public void tearDown() {
118129

119130
@ParameterizedTest
120131
@MethodSource("resourceFileParams")
121-
public void When_MappingDiagnosticReportJson_Expect_CompoundStatementXmlOutput(String inputJson, String outputXml) {
132+
void When_MappingDiagnosticReportJson_Expect_CompoundStatementXmlOutput(String inputJson, String outputXml) {
122133
final CharSequence expectedOutputMessage = ResourceTestFileUtils.getFileContent(TEST_FILE_DIRECTORY + outputXml);
123-
final String jsonInput = ResourceTestFileUtils.getFileContent(TEST_FILE_DIRECTORY + inputJson);
124-
final DiagnosticReport diagnosticReport = new FhirParseService().parseResource(jsonInput, DiagnosticReport.class);
134+
final DiagnosticReport diagnosticReport = getDiagnosticReportResourceFromJson(inputJson);
125135

126136
final String outputMessage = mapper.mapDiagnosticReportToCompoundStatement(diagnosticReport);
137+
127138
assertThat(removeLineEndings(outputMessage)).isEqualTo(removeLineEndings(expectedOutputMessage.toString()));
128139
}
129140

141+
@Test
142+
void When_DiagnosticReport_With_NopatMetaSecurity_Expect_ConfidentialityCodeWithinCompoundStatement() {
143+
final String testFile = "diagnostic-report-with-multi-specimens-nopat.json";
144+
final DiagnosticReport diagnosticReport = getDiagnosticReportResourceFromJson(testFile);
145+
146+
when(confidentialityService.generateConfidentialityCode(diagnosticReport))
147+
.thenReturn(Optional.of(NOPAT_CONFIDENTIALITY_CODE));
148+
149+
final String result = mapper.mapDiagnosticReportToCompoundStatement(diagnosticReport);
150+
151+
assertAll(
152+
() -> assertThat(result).contains(NOPAT_CONFIDENTIALITY_CODE),
153+
() -> assertThat(ConfidentialityCodeUtility.getSecurityCodeFromResource(diagnosticReport)).isEqualTo("NOPAT")
154+
);
155+
}
156+
157+
@Test
158+
void When_DiagnosticReport_With_NoscrubMetaSecurity_Expect_ConfidentialityCodeNotWithinCompoundStatement() {
159+
final String testFile = "diagnostic-report-with-multi-specimens-noscrub.json";
160+
final DiagnosticReport diagnosticReport = getDiagnosticReportResourceFromJson(testFile);
161+
162+
when(confidentialityService.generateConfidentialityCode(diagnosticReport))
163+
.thenReturn(Optional.empty());
164+
165+
final String result = mapper.mapDiagnosticReportToCompoundStatement(diagnosticReport);
166+
167+
assertAll(
168+
() -> assertThat(result).doesNotContain(NOPAT_CONFIDENTIALITY_CODE),
169+
() -> assertThat(ConfidentialityCodeUtility.getSecurityCodeFromResource(diagnosticReport)).isEqualTo("NOSCRUB")
170+
);
171+
}
172+
173+
private DiagnosticReport getDiagnosticReportResourceFromJson(String filename) {
174+
final String filePath = TEST_FILE_DIRECTORY + filename;
175+
return FileParsingUtility.parseResourceFromJsonFile(filePath, DiagnosticReport.class);
176+
}
177+
130178
private String removeLineEndings(String input) {
131179
return input.replace("\n", "").replace("\r", "");
132180
}
@@ -171,5 +219,4 @@ private Answer<String> mockSpecimenMapping() {
171219
return String.format("<!-- Mapped Specimen with id: %s -->", specimen.getId());
172220
};
173221
}
174-
175-
}
222+
}

0 commit comments

Comments
 (0)