mirror of
https://github.com/pcvolkmer/etl-processor.git
synced 2025-07-01 14:12:55 +00:00
fix: * Status prüfung gIcs überarbeitet.* Tests für GicsConsentService implementiert. * Überschreiben des MTB-File Consent, falls gICS aktiviert ist
This commit is contained in:
@ -59,40 +59,3 @@ services:
|
|||||||
# POSTGRES_DB: dev
|
# POSTGRES_DB: dev
|
||||||
# POSTGRES_USER: dev
|
# POSTGRES_USER: dev
|
||||||
# POSTGRES_PASSWORD: dev
|
# POSTGRES_PASSWORD: dev
|
||||||
|
|
||||||
|
|
||||||
mysql:
|
|
||||||
image: mysql:8
|
|
||||||
container_name: gics-mysql
|
|
||||||
restart: unless-stopped
|
|
||||||
environment:
|
|
||||||
MYSQL_ROOT_PASSWORD: root
|
|
||||||
TZ: Europe/Berlin
|
|
||||||
ports:
|
|
||||||
- "3306:3306"
|
|
||||||
volumes:
|
|
||||||
- ./sqls:/docker-entrypoint-initdb.d
|
|
||||||
command: --max_allowed_packet=20M --default-time-zone=Europe/Berlin
|
|
||||||
|
|
||||||
gics:
|
|
||||||
image: registry.diz.uni-marburg.de/ths/gics:2023.1.3
|
|
||||||
container_name: gics-wildfly
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
|
||||||
- "8090:8080"
|
|
||||||
- "127.0.0.1:9992:9990"
|
|
||||||
extra_hosts:
|
|
||||||
- "host.docker.internal:host-gateway"
|
|
||||||
depends_on:
|
|
||||||
- mysql
|
|
||||||
|
|
||||||
consent-data-loader:
|
|
||||||
image: confluentinc/cp-kafkacat:7.1.12
|
|
||||||
entrypoint: ["/bin/bash", "-c"]
|
|
||||||
command: >
|
|
||||||
"kafkacat -b kafka:19092 -K: -t consent-json -P -l /data/consent-data.ndjson"
|
|
||||||
volumes:
|
|
||||||
- ./consent-data.ndjson:/data/consent-data.ndjson:ro
|
|
||||||
depends_on:
|
|
||||||
kafka:
|
|
||||||
condition: service_healthy
|
|
@ -1,12 +1,14 @@
|
|||||||
package dev.dnpm.etl.processor.consent;
|
package dev.dnpm.etl.processor.consent;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
import dev.dnpm.etl.processor.config.AppFhirConfig;
|
import dev.dnpm.etl.processor.config.AppFhirConfig;
|
||||||
import dev.dnpm.etl.processor.config.GIcsConfigProperties;
|
import dev.dnpm.etl.processor.config.GIcsConfigProperties;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.hl7.fhir.r4.model.BooleanType;
|
import org.hl7.fhir.r4.model.BooleanType;
|
||||||
import org.hl7.fhir.r4.model.Coding;
|
import org.hl7.fhir.r4.model.Coding;
|
||||||
import org.hl7.fhir.r4.model.Identifier;
|
import org.hl7.fhir.r4.model.Identifier;
|
||||||
|
import org.hl7.fhir.r4.model.OperationOutcome;
|
||||||
import org.hl7.fhir.r4.model.Parameters;
|
import org.hl7.fhir.r4.model.Parameters;
|
||||||
import org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent;
|
import org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent;
|
||||||
import org.hl7.fhir.r4.model.StringType;
|
import org.hl7.fhir.r4.model.StringType;
|
||||||
@ -31,7 +33,7 @@ public class GicsConsentService implements ICheckConsent {
|
|||||||
|
|
||||||
private final GIcsConfigProperties gIcsConfigProperties;
|
private final GIcsConfigProperties gIcsConfigProperties;
|
||||||
|
|
||||||
public final String IS_CONSENTED_PATH = "/ttp-fhir/fhir/gics/$isConsented";
|
public static final String IS_CONSENTED_ENDPOINT = "/$isConsented";
|
||||||
private final RetryTemplate retryTemplate;
|
private final RetryTemplate retryTemplate;
|
||||||
private final RestTemplate restTemplate;
|
private final RestTemplate restTemplate;
|
||||||
private final FhirContext fhirContext;
|
private final FhirContext fhirContext;
|
||||||
@ -56,8 +58,7 @@ public class GicsConsentService implements ICheckConsent {
|
|||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"gICS base URL is empty - should call gICS with false configuration.");
|
"gICS base URL is empty - should call gICS with false configuration.");
|
||||||
}
|
}
|
||||||
url = UriComponentsBuilder.fromHttpUrl(gIcsBaseUri)
|
url = UriComponentsBuilder.fromHttpUrl(gIcsBaseUri).path(IS_CONSENTED_ENDPOINT)
|
||||||
.path(IS_CONSENTED_PATH)
|
|
||||||
.toUriString();
|
.toUriString();
|
||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
@ -84,14 +85,20 @@ public class GicsConsentService implements ICheckConsent {
|
|||||||
.setSystem(configProperties.getPersonIdentifierSystem())));
|
.setSystem(configProperties.getPersonIdentifierSystem())));
|
||||||
result.addParameter(new ParametersParameterComponent().setName("domain")
|
result.addParameter(new ParametersParameterComponent().setName("domain")
|
||||||
.setValue(new StringType().setValue(configProperties.getConsentDomainName())));
|
.setValue(new StringType().setValue(configProperties.getConsentDomainName())));
|
||||||
result.addParameter(new ParametersParameterComponent().setName("policy")
|
result.addParameter(new ParametersParameterComponent().setName("policy").setValue(
|
||||||
.setValue(new Coding().setCode(configProperties.getPolicyCode())
|
new Coding().setCode(configProperties.getPolicyCode())
|
||||||
.setSystem(configProperties.getPolicySystem())));
|
.setSystem(configProperties.getPolicySystem())));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* is mandatory parameter, but we ignore it via additional configuration parameter
|
||||||
|
* 'ignoreVersionNumber'.
|
||||||
|
*/
|
||||||
result.addParameter(new ParametersParameterComponent().setName("version")
|
result.addParameter(new ParametersParameterComponent().setName("version")
|
||||||
.setValue(new StringType().setValue(configProperties.getParameterVersion())));
|
.setValue(new StringType().setValue("1.1")));
|
||||||
|
|
||||||
/* add config parameter with:
|
/* add config parameter with:
|
||||||
* ignoreVersionNumber -> true
|
* ignoreVersionNumber -> true ->> Reason is we cannot know which policy version each patient
|
||||||
|
* has possibly signed or not, therefore we are happy with any version found.
|
||||||
* unknownStateIsConsideredAsDecline -> true
|
* unknownStateIsConsideredAsDecline -> true
|
||||||
*/
|
*/
|
||||||
var config = new ParametersParameterComponent().setName("config").addPart(
|
var config = new ParametersParameterComponent().setName("config").addPart(
|
||||||
@ -110,9 +117,10 @@ public class GicsConsentService implements ICheckConsent {
|
|||||||
HttpEntity<String> requestEntity = new HttpEntity<>(parameterAsXml, this.httpHeader);
|
HttpEntity<String> requestEntity = new HttpEntity<>(parameterAsXml, this.httpHeader);
|
||||||
ResponseEntity<String> responseEntity;
|
ResponseEntity<String> responseEntity;
|
||||||
try {
|
try {
|
||||||
|
var url = getGicsUri();
|
||||||
|
|
||||||
responseEntity = retryTemplate.execute(
|
responseEntity = retryTemplate.execute(
|
||||||
ctx -> restTemplate.exchange(getGicsUri(), HttpMethod.POST, requestEntity,
|
ctx -> restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class));
|
||||||
String.class));
|
|
||||||
} catch (RestClientException e) {
|
} catch (RestClientException e) {
|
||||||
var msg = String.format("Get consents status request failed reason: '%s",
|
var msg = String.format("Get consents status request failed reason: '%s",
|
||||||
e.getMessage());
|
e.getMessage());
|
||||||
@ -123,8 +131,7 @@ public class GicsConsentService implements ICheckConsent {
|
|||||||
var msg = String.format(
|
var msg = String.format(
|
||||||
"Get consents status process has been terminated. termination reason: '%s",
|
"Get consents status process has been terminated. termination reason: '%s",
|
||||||
terminatedRetryException.getMessage());
|
terminatedRetryException.getMessage());
|
||||||
log.error(msg
|
log.error(msg);
|
||||||
);
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -153,8 +160,10 @@ public class GicsConsentService implements ICheckConsent {
|
|||||||
if (consentStatusResponse == null) {
|
if (consentStatusResponse == null) {
|
||||||
return TtpConsentStatus.FAILED_TO_ASK;
|
return TtpConsentStatus.FAILED_TO_ASK;
|
||||||
}
|
}
|
||||||
var responseParameters = fhirContext.newJsonParser()
|
try {
|
||||||
.parseResource(Parameters.class, consentStatusResponse);
|
var response = fhirContext.newJsonParser().parseResource(consentStatusResponse);
|
||||||
|
|
||||||
|
if (response instanceof Parameters responseParameters) {
|
||||||
|
|
||||||
var responseValue = responseParameters.getParameter("consented").getValue();
|
var responseValue = responseParameters.getParameter("consented").getValue();
|
||||||
var isConsented = responseValue.castToBoolean(responseValue);
|
var isConsented = responseValue.castToBoolean(responseValue);
|
||||||
@ -166,5 +175,16 @@ public class GicsConsentService implements ICheckConsent {
|
|||||||
} else {
|
} else {
|
||||||
return TtpConsentStatus.CONSENT_MISSING_OR_REJECTED;
|
return TtpConsentStatus.CONSENT_MISSING_OR_REJECTED;
|
||||||
}
|
}
|
||||||
|
} else if (response instanceof OperationOutcome outcome) {
|
||||||
|
|
||||||
|
log.error(
|
||||||
|
"failed to get consent status from ttp. probably configuration error. outcome: ",
|
||||||
|
fhirContext.newJsonParser().encodeToString(outcome));
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (DataFormatException dfe) {
|
||||||
|
log.error("failed to parse response to FHIR R4 resource.", dfe);
|
||||||
|
}
|
||||||
|
return TtpConsentStatus.FAILED_TO_ASK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,8 +92,7 @@ data class GIcsConfigProperties(
|
|||||||
/**
|
/**
|
||||||
* Consent Policy which should be used for consent check
|
* Consent Policy which should be used for consent check
|
||||||
*/
|
*/
|
||||||
val policySystem: String = "urn:oid:2.16.840.1.113883.3.1937.777.24.5.3",
|
val policySystem: String = "urn:oid:2.16.840.1.113883.3.1937.777.24.5.3"
|
||||||
val parameterVersion: String = "1.1"
|
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
const val NAME = "app.consent.gics"
|
const val NAME = "app.consent.gics"
|
||||||
|
@ -47,18 +47,9 @@ class MtbFileRestController(
|
|||||||
|
|
||||||
@PostMapping(consumes = [MediaType.APPLICATION_JSON_VALUE])
|
@PostMapping(consumes = [MediaType.APPLICATION_JSON_VALUE])
|
||||||
fun mtbFile(@RequestBody mtbFile: MtbFile): ResponseEntity<Unit> {
|
fun mtbFile(@RequestBody mtbFile: MtbFile): ResponseEntity<Unit> {
|
||||||
var ttpConsentStatus = constService.isConsented(mtbFile.patient.id)
|
val consentStatusBooleanPair = checkConsentStatus(mtbFile)
|
||||||
|
var ttpConsentStatus = consentStatusBooleanPair.first
|
||||||
// received status REJECTED overrides TTP value. Also in case of disabled consent service,
|
val isConsentOK = consentStatusBooleanPair.second
|
||||||
// we need to override IGNORED status
|
|
||||||
if (mtbFile.consent.status == Consent.Status.REJECTED) ttpConsentStatus =
|
|
||||||
TtpConsentStatus.CONSENT_MISSING_OR_REJECTED
|
|
||||||
|
|
||||||
val isConsentOK = mtbFile.consent.status == Consent.Status.ACTIVE && (ttpConsentStatus.equals(
|
|
||||||
TtpConsentStatus.CONSENTED
|
|
||||||
) || ttpConsentStatus.equals(
|
|
||||||
TtpConsentStatus.IGNORED
|
|
||||||
))
|
|
||||||
if (isConsentOK) {
|
if (isConsentOK) {
|
||||||
logger.debug("Accepted MTB File (bwHC V1) for processing")
|
logger.debug("Accepted MTB File (bwHC V1) for processing")
|
||||||
requestProcessor.processMtbFile(mtbFile)
|
requestProcessor.processMtbFile(mtbFile)
|
||||||
@ -71,6 +62,21 @@ class MtbFileRestController(
|
|||||||
return ResponseEntity.accepted().build()
|
return ResponseEntity.accepted().build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun checkConsentStatus(mtbFile: MtbFile): Pair<TtpConsentStatus, Boolean> {
|
||||||
|
var ttpConsentStatus = constService.isConsented(mtbFile.patient.id)
|
||||||
|
|
||||||
|
val isConsentOK =
|
||||||
|
(ttpConsentStatus.equals(TtpConsentStatus.IGNORED) && mtbFile.consent.status == Consent.Status.ACTIVE) ||
|
||||||
|
ttpConsentStatus.equals(
|
||||||
|
TtpConsentStatus.CONSENTED
|
||||||
|
)
|
||||||
|
if (ttpConsentStatus.equals(TtpConsentStatus.IGNORED) && mtbFile.consent.status == Consent.Status.REJECTED) {
|
||||||
|
// in case ttp check is disabled - we propagate rejected status anyway
|
||||||
|
ttpConsentStatus = TtpConsentStatus.CONSENT_MISSING_OR_REJECTED
|
||||||
|
}
|
||||||
|
return Pair(ttpConsentStatus, isConsentOK)
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping(consumes = [CustomMediaType.APPLICATION_VND_DNPM_V2_MTB_JSON_VALUE])
|
@PostMapping(consumes = [CustomMediaType.APPLICATION_VND_DNPM_V2_MTB_JSON_VALUE])
|
||||||
fun mtbFile(@RequestBody mtbFile: Mtb): ResponseEntity<Unit> {
|
fun mtbFile(@RequestBody mtbFile: Mtb): ResponseEntity<Unit> {
|
||||||
logger.debug("Accepted MTB File (DNPM V2) for processing")
|
logger.debug("Accepted MTB File (DNPM V2) for processing")
|
||||||
|
@ -1,14 +1,102 @@
|
|||||||
package dev.dnpm.etl.processor.consent;
|
package dev.dnpm.etl.processor.consent;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
|
||||||
|
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import dev.dnpm.etl.processor.config.AppConfiguration;
|
||||||
|
import dev.dnpm.etl.processor.config.AppFhirConfig;
|
||||||
|
import org.hl7.fhir.r4.model.BooleanType;
|
||||||
|
import org.hl7.fhir.r4.model.OperationOutcome;
|
||||||
|
import org.hl7.fhir.r4.model.OperationOutcome.IssueSeverity;
|
||||||
|
import org.hl7.fhir.r4.model.OperationOutcome.IssueType;
|
||||||
|
import org.hl7.fhir.r4.model.OperationOutcome.OperationOutcomeIssueComponent;
|
||||||
|
import org.hl7.fhir.r4.model.Parameters;
|
||||||
|
import org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.TestPropertySource;
|
||||||
|
import org.springframework.test.web.client.MockRestServiceServer;
|
||||||
|
|
||||||
//@ExtendWith(MockitoExtension.class)
|
|
||||||
|
|
||||||
|
@ContextConfiguration(classes = {GicsConsentService.class,
|
||||||
|
AppConfiguration.class, ObjectMapper.class})
|
||||||
|
@TestPropertySource(properties = {"app.consent.gics.enabled=true",
|
||||||
|
"app.consent.gics.gIcsBaseUri=http://localhost:8090/ttp-fhir/fhir/gics"})
|
||||||
|
@RestClientTest
|
||||||
public class GicsConsentServiceTest {
|
public class GicsConsentServiceTest {
|
||||||
|
|
||||||
|
public static final String GICS_BASE_URI = "http://localhost:8090/ttp-fhir/fhir/gics";
|
||||||
|
@Autowired
|
||||||
|
MockRestServiceServer mockRestServiceServer;
|
||||||
|
@Autowired
|
||||||
|
GicsConsentService gicsConsentService;
|
||||||
|
@Autowired
|
||||||
|
AppConfiguration appConfiguration;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
AppFhirConfig appFhirConfig;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setUp() {
|
||||||
|
mockRestServiceServer = MockRestServiceServer.createServer(appConfiguration.restTemplate());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void isConsented() {
|
void isConsented() {
|
||||||
|
final Parameters responseConsented = new Parameters().addParameter(
|
||||||
|
new ParametersParameterComponent().setName("consented")
|
||||||
|
.setValue(new BooleanType().setValue(true)));
|
||||||
|
|
||||||
|
mockRestServiceServer.expect(
|
||||||
|
requestTo("http://localhost:8090/ttp-fhir/fhir/gics" + GicsConsentService.IS_CONSENTED_ENDPOINT)).andRespond(
|
||||||
|
withSuccess(appFhirConfig.fhirContext().newJsonParser()
|
||||||
|
.encodeResourceToString(responseConsented),
|
||||||
|
MediaType.APPLICATION_JSON));
|
||||||
|
|
||||||
|
var consentStatus = gicsConsentService.isConsented("123456");
|
||||||
|
assertThat(consentStatus).isEqualTo(TtpConsentStatus.CONSENTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void consentRevoced() {
|
||||||
|
final Parameters responseRevoced = new Parameters().addParameter(
|
||||||
|
new ParametersParameterComponent().setName("consented")
|
||||||
|
.setValue(new BooleanType().setValue(false)));
|
||||||
|
|
||||||
|
mockRestServiceServer.expect(
|
||||||
|
requestTo("http://localhost:8090/ttp-fhir/fhir/gics" + GicsConsentService.IS_CONSENTED_ENDPOINT)).andRespond(
|
||||||
|
withSuccess(appFhirConfig.fhirContext().newJsonParser()
|
||||||
|
.encodeResourceToString(responseRevoced),
|
||||||
|
MediaType.APPLICATION_JSON));
|
||||||
|
|
||||||
|
var consentStatus = gicsConsentService.isConsented("123456");
|
||||||
|
assertThat(consentStatus).isEqualTo(TtpConsentStatus.CONSENT_MISSING_OR_REJECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void gicsParameterInvalid() {
|
||||||
|
final OperationOutcome responseErrorOutcome = new OperationOutcome().addIssue(
|
||||||
|
new OperationOutcomeIssueComponent().setSeverity(
|
||||||
|
IssueSeverity.ERROR).setCode(IssueType.PROCESSING)
|
||||||
|
.setDiagnostics("Invalid policy parameter..."));
|
||||||
|
|
||||||
|
mockRestServiceServer.expect(
|
||||||
|
requestTo(GICS_BASE_URI + GicsConsentService.IS_CONSENTED_ENDPOINT)).andRespond(
|
||||||
|
withSuccess(appFhirConfig.fhirContext().newJsonParser()
|
||||||
|
.encodeResourceToString(responseErrorOutcome),
|
||||||
|
MediaType.APPLICATION_JSON));
|
||||||
|
|
||||||
|
var consentStatus = gicsConsentService.isConsented("123456");
|
||||||
|
assertThat(consentStatus).isEqualTo(TtpConsentStatus.FAILED_TO_ASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,22 +21,29 @@ package dev.dnpm.etl.processor.input
|
|||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import de.ukw.ccc.bwhc.dto.*
|
import de.ukw.ccc.bwhc.dto.*
|
||||||
import dev.dnpm.etl.processor.consent.ConsentCheckedIgnored
|
import de.ukw.ccc.bwhc.dto.Consent.Status
|
||||||
import dev.dnpm.etl.processor.consent.TtpConsentStatus
|
|
||||||
import dev.dnpm.etl.processor.CustomMediaType
|
import dev.dnpm.etl.processor.CustomMediaType
|
||||||
|
import dev.dnpm.etl.processor.consent.ConsentCheckedIgnored
|
||||||
|
import dev.dnpm.etl.processor.consent.GicsConsentService
|
||||||
|
import dev.dnpm.etl.processor.consent.TtpConsentStatus
|
||||||
import dev.dnpm.etl.processor.services.RequestProcessor
|
import dev.dnpm.etl.processor.services.RequestProcessor
|
||||||
import dev.pcvolkmer.mv64e.mtb.Mtb
|
import dev.pcvolkmer.mv64e.mtb.Mtb
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.junit.jupiter.api.Nested
|
import org.junit.jupiter.api.Nested
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.extension.ExtendWith
|
import org.junit.jupiter.api.extension.ExtendWith
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest
|
||||||
|
import org.junit.jupiter.params.provider.ValueSource
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
import org.mockito.Mockito.*
|
import org.mockito.Mockito.times
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
import org.mockito.junit.jupiter.MockitoExtension
|
import org.mockito.junit.jupiter.MockitoExtension
|
||||||
import org.mockito.kotlin.any
|
import org.mockito.kotlin.any
|
||||||
import org.mockito.kotlin.anyValueClass
|
import org.mockito.kotlin.anyValueClass
|
||||||
|
import org.mockito.kotlin.whenever
|
||||||
import org.springframework.core.io.ClassPathResource
|
import org.springframework.core.io.ClassPathResource
|
||||||
import org.springframework.http.MediaType
|
import org.springframework.http.MediaType
|
||||||
|
import org.springframework.test.context.TestPropertySource
|
||||||
import org.springframework.test.web.servlet.MockMvc
|
import org.springframework.test.web.servlet.MockMvc
|
||||||
import org.springframework.test.web.servlet.delete
|
import org.springframework.test.web.servlet.delete
|
||||||
import org.springframework.test.web.servlet.post
|
import org.springframework.test.web.servlet.post
|
||||||
@ -54,6 +61,7 @@ class MtbFileRestControllerTest {
|
|||||||
|
|
||||||
private lateinit var requestProcessor: RequestProcessor
|
private lateinit var requestProcessor: RequestProcessor
|
||||||
|
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
fun setup(
|
fun setup(
|
||||||
@Mock requestProcessor: RequestProcessor
|
@Mock requestProcessor: RequestProcessor
|
||||||
@ -66,7 +74,7 @@ class MtbFileRestControllerTest {
|
|||||||
@Test
|
@Test
|
||||||
fun shouldProcessPostRequest() {
|
fun shouldProcessPostRequest() {
|
||||||
mockMvc.post("/mtbfile") {
|
mockMvc.post("/mtbfile") {
|
||||||
content = objectMapper.writeValueAsString(bwhcMtbFileContent(Consent.Status.ACTIVE))
|
content = objectMapper.writeValueAsString(bwhcMtbFileContent(Status.ACTIVE))
|
||||||
contentType = MediaType.APPLICATION_JSON
|
contentType = MediaType.APPLICATION_JSON
|
||||||
}.andExpect {
|
}.andExpect {
|
||||||
status {
|
status {
|
||||||
@ -81,7 +89,7 @@ class MtbFileRestControllerTest {
|
|||||||
fun shouldProcessPostRequestWithRejectedConsent() {
|
fun shouldProcessPostRequestWithRejectedConsent() {
|
||||||
mockMvc.post("/mtbfile") {
|
mockMvc.post("/mtbfile") {
|
||||||
content =
|
content =
|
||||||
objectMapper.writeValueAsString(bwhcMtbFileContent(Consent.Status.REJECTED))
|
objectMapper.writeValueAsString(bwhcMtbFileContent(Status.REJECTED))
|
||||||
contentType = MediaType.APPLICATION_JSON
|
contentType = MediaType.APPLICATION_JSON
|
||||||
}.andExpect {
|
}.andExpect {
|
||||||
status {
|
status {
|
||||||
@ -110,6 +118,93 @@ class MtbFileRestControllerTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestPropertySource(
|
||||||
|
properties = ["app.consent.gics.enabled=true",
|
||||||
|
"app.consent.gics.gIcsBaseUri=http://localhost:8090/ttp-fhir/fhir/gics"]
|
||||||
|
)
|
||||||
|
@Nested
|
||||||
|
inner class BwhcRequestsCheckConsentViaTtp {
|
||||||
|
|
||||||
|
private lateinit var mockMvc: MockMvc
|
||||||
|
|
||||||
|
private lateinit var requestProcessor: RequestProcessor
|
||||||
|
|
||||||
|
private lateinit var gicsConsentService: GicsConsentService
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
fun setup(
|
||||||
|
@Mock requestProcessor: RequestProcessor,
|
||||||
|
@Mock gicsConsentService: GicsConsentService
|
||||||
|
) {
|
||||||
|
this.requestProcessor = requestProcessor
|
||||||
|
val controller = MtbFileRestController(requestProcessor, gicsConsentService)
|
||||||
|
this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build()
|
||||||
|
this.gicsConsentService = gicsConsentService
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(strings = ["ACTIVE", "REJECTED"])
|
||||||
|
fun shouldProcessPostRequest(status: String) {
|
||||||
|
|
||||||
|
whenever(gicsConsentService.isConsented(any())).thenReturn(TtpConsentStatus.CONSENTED)
|
||||||
|
|
||||||
|
mockMvc.post("/mtbfile") {
|
||||||
|
content =
|
||||||
|
objectMapper.writeValueAsString(bwhcMtbFileContent(Status.valueOf(status)))
|
||||||
|
contentType = MediaType.APPLICATION_JSON
|
||||||
|
}.andExpect {
|
||||||
|
status {
|
||||||
|
isAccepted()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
verify(requestProcessor, times(1)).processMtbFile(any<MtbFile>())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(strings = ["ACTIVE", "REJECTED"])
|
||||||
|
fun shouldProcessPostRequestWithRejectedConsent(status: String) {
|
||||||
|
|
||||||
|
whenever(gicsConsentService.isConsented(any())).thenReturn(TtpConsentStatus.CONSENT_MISSING_OR_REJECTED)
|
||||||
|
|
||||||
|
mockMvc.post("/mtbfile") {
|
||||||
|
content =
|
||||||
|
objectMapper.writeValueAsString(bwhcMtbFileContent(Status.valueOf(status)))
|
||||||
|
contentType = MediaType.APPLICATION_JSON
|
||||||
|
}.andExpect {
|
||||||
|
status {
|
||||||
|
isAccepted()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// consent status from ttp should override file consent value
|
||||||
|
verify(requestProcessor, times(1)).processDeletion(
|
||||||
|
anyValueClass(),
|
||||||
|
org.mockito.kotlin.eq(TtpConsentStatus.CONSENT_MISSING_OR_REJECTED)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun shouldProcessDeleteRequest() {
|
||||||
|
|
||||||
|
mockMvc.delete("/mtbfile/TEST_12345678").andExpect {
|
||||||
|
status {
|
||||||
|
isAccepted()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
verify(requestProcessor, times(1)).processDeletion(
|
||||||
|
anyValueClass(),
|
||||||
|
org.mockito.kotlin.eq(TtpConsentStatus.IGNORED)
|
||||||
|
)
|
||||||
|
verify(gicsConsentService, times(0)).isConsented(any())
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
inner class BwhcRequestsWithAlias {
|
inner class BwhcRequestsWithAlias {
|
||||||
|
|
||||||
@ -129,7 +224,7 @@ class MtbFileRestControllerTest {
|
|||||||
@Test
|
@Test
|
||||||
fun shouldProcessPostRequest() {
|
fun shouldProcessPostRequest() {
|
||||||
mockMvc.post("/mtb") {
|
mockMvc.post("/mtb") {
|
||||||
content = objectMapper.writeValueAsString(bwhcMtbFileContent(Consent.Status.ACTIVE))
|
content = objectMapper.writeValueAsString(bwhcMtbFileContent(Status.ACTIVE))
|
||||||
contentType = MediaType.APPLICATION_JSON
|
contentType = MediaType.APPLICATION_JSON
|
||||||
}.andExpect {
|
}.andExpect {
|
||||||
status {
|
status {
|
||||||
@ -144,7 +239,7 @@ class MtbFileRestControllerTest {
|
|||||||
fun shouldProcessPostRequestWithRejectedConsent() {
|
fun shouldProcessPostRequestWithRejectedConsent() {
|
||||||
mockMvc.post("/mtb") {
|
mockMvc.post("/mtb") {
|
||||||
content =
|
content =
|
||||||
objectMapper.writeValueAsString(bwhcMtbFileContent(Consent.Status.REJECTED))
|
objectMapper.writeValueAsString(bwhcMtbFileContent(Status.REJECTED))
|
||||||
contentType = MediaType.APPLICATION_JSON
|
contentType = MediaType.APPLICATION_JSON
|
||||||
}.andExpect {
|
}.andExpect {
|
||||||
status {
|
status {
|
||||||
@ -212,7 +307,7 @@ class MtbFileRestControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun bwhcMtbFileContent(consentStatus: Consent.Status) = MtbFile.builder()
|
fun bwhcMtbFileContent(consentStatus: Status) = MtbFile.builder()
|
||||||
.withPatient(
|
.withPatient(
|
||||||
Patient.builder()
|
Patient.builder()
|
||||||
.withId("TEST_12345678")
|
.withId("TEST_12345678")
|
||||||
|
Reference in New Issue
Block a user