From fcb962510125853ad3299f6cc54b0c32bd93d52a Mon Sep 17 00:00:00 2001 From: Volker Schmidt Date: Fri, 16 Aug 2019 16:37:59 +0200 Subject: [PATCH] Adds REST interface tests for FHIR QuestionnaireResponse. --- .../AbstractProgramStageFhirRestAppTest.java | 5 + ...tionnaireResponseEventFhirRestAppTest.java | 372 ++++++++++++++++++ .../dhis/test/default-event-91-get.json | 27 ++ .../default-event-91-update-response.json | 11 + .../dhis/test/default-event-91-update.json | 22 ++ .../dhis/test/single-event-91-get.json | 23 ++ .../fhir/metadata/model/ProgramStageRule.java | 4 +- .../repository/CustomRuleRepository.java | 1 - .../impl/CustomRuleRepositoryImpl.java | 19 + .../dhis/impl/DhisToFhirRequestResolver.java | 2 +- .../DhisToFhirTransformerServiceImpl.java | 4 +- .../EnrollmentToFhirRequestResolver.java | 2 +- ...ractDhisMetadataToFhirRequestResolver.java | 5 +- .../ProgramStageToFhirRequestResolver.java | 10 +- .../TrackedEntityToFhirRequestResolver.java | 2 +- 15 files changed, 494 insertions(+), 15 deletions(-) create mode 100644 app/src/test/java/org/dhis2/fhir/adapter/fhir/server/r4/R4QuestionnaireResponseEventFhirRestAppTest.java create mode 100644 app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-event-91-get.json create mode 100644 app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-event-91-update-response.json create mode 100644 app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-event-91-update.json create mode 100644 app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/single-event-91-get.json diff --git a/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/AbstractProgramStageFhirRestAppTest.java b/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/AbstractProgramStageFhirRestAppTest.java index a3a9ca94..00d87771 100644 --- a/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/AbstractProgramStageFhirRestAppTest.java +++ b/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/AbstractProgramStageFhirRestAppTest.java @@ -78,5 +78,10 @@ protected void expectProgramStageMetadataRequests() throws Exception "program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType," + "optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D%5D&filter=name:eq:Child%20Programme" ) ) .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-program.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); + systemDhis2Server.expect( ExpectedCount.between( 0, 1 ), method( HttpMethod.GET ) ).andExpect( header( "Authorization", testConfiguration.getDhis2SystemAuthorization() ) ) + .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programStages/MsWxkiY6tMS.json?fields=id,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart," + + "programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D" ) ) + .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-program-stage.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); + } } diff --git a/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/r4/R4QuestionnaireResponseEventFhirRestAppTest.java b/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/r4/R4QuestionnaireResponseEventFhirRestAppTest.java new file mode 100644 index 00000000..a3b07489 --- /dev/null +++ b/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/r4/R4QuestionnaireResponseEventFhirRestAppTest.java @@ -0,0 +1,372 @@ +package org.dhis2.fhir.adapter.fhir.server.r4; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.client.api.IGenericClient; +import ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor; +import ca.uhn.fhir.rest.server.exceptions.AuthenticationException; +import org.apache.commons.io.IOUtils; +import org.dhis2.fhir.adapter.dhis.tracker.program.EventStatus; +import org.dhis2.fhir.adapter.fhir.extension.DueDateExtensionUtils; +import org.dhis2.fhir.adapter.fhir.extension.EventStatusExtensionUtils; +import org.dhis2.fhir.adapter.fhir.extension.LocationExtensionUtils; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.server.AbstractProgramStageFhirRestAppTest; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.QuestionnaireResponse; +import org.hl7.fhir.r4.model.Reference; +import org.hl7.fhir.r4.model.ResourceFactory; +import org.junit.Assert; +import org.junit.Test; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.test.web.client.ExpectedCount; + +import javax.annotation.Nonnull; +import java.nio.charset.StandardCharsets; +import java.sql.Date; +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.Objects; + +import static org.springframework.test.web.client.match.MockRestRequestMatchers.*; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; + +/** + * R4 tests for rest interfaces that access DHIS2 events by using FHIR Questionnaire Responses. + * Some methods are executed twice in order to verify that no cached data is used without authentication. + * + * @author volsch + */ +public class R4QuestionnaireResponseEventFhirRestAppTest extends AbstractProgramStageFhirRestAppTest +{ + @Nonnull + @Override + protected FhirVersion getFhirVersion() + { + return FhirVersion.R4; + } + + @Test( expected = AuthenticationException.class ) + public void getQuestionnaireResponseWithoutAuthorization() + { + final IGenericClient client = createGenericClient(); + client.read().resource( QuestionnaireResponse.class ).withId( "deR4kl4mnf7" ).execute(); + } + + @Test( expected = AuthenticationException.class ) + public void getQuestionnaireResponseWithInvalidAuthorization() throws Exception + { + expectProgramStageMetadataRequests(); + userDhis2Server.expect( ExpectedCount.once(), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6aW52YWxpZF8x" ) ) + .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events/deR4kl4mnf7.json?fields=deleted,event,orgUnit,program,enrollment,trackedEntityInstance,programStage,status,eventDate,dueDate,coordinate,lastUpdated," + + "dataValues%5BdataElement,value,providedElsewhere,lastUpdated,storedBy%5D" ) ) + .andRespond( withStatus( HttpStatus.UNAUTHORIZED ) ); + + final IGenericClient client = createGenericClient(); + client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "invalid_1" ) ); + client.read().resource( QuestionnaireResponse.class ).withId( "deR4kl4mnf7" ).execute(); + } + + @Test + public void getQuestionnaireResponseRepeated() throws Exception + { + getQuestionnaireResponse(); + getQuestionnaireResponse(); + } + + private void getQuestionnaireResponse() throws Exception + { + systemDhis2Server.reset(); + userDhis2Server.reset(); + + expectProgramStageMetadataRequests(); + userDhis2Server.expect( ExpectedCount.once(), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) ) + .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events/deR4kl4mnf7.json?fields=deleted,event,orgUnit,program,enrollment,trackedEntityInstance,programStage,status,eventDate,dueDate,coordinate,lastUpdated," + + "dataValues%5BdataElement,value,providedElsewhere,lastUpdated,storedBy%5D" ) ) + .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-event-91-get.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); + + final IGenericClient client = createGenericClient(); + client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) ); + QuestionnaireResponse questionnaireResponse = client.read().resource( QuestionnaireResponse.class ).withId( "deR4kl4mnf7" ).execute(); + Assert.assertEquals( "Patient/JeR2Ul4mZfx", questionnaireResponse.getSubject().getReference() ); + Assert.assertEquals( "Location/ldXIdLNUNEn", + Objects.requireNonNull( LocationExtensionUtils.getValue( questionnaireResponse ) ).getReferenceElement().getValue() ); + + systemDhis2Server.verify(); + userDhis2Server.verify(); + } + + @Test( expected = AuthenticationException.class ) + public void searchQuestionnaireResponseWithoutAuthorization() throws Exception + { + expectProgramStageMetadataRequests(); + final IGenericClient client = createGenericClient(); + client.search().forResource( QuestionnaireResponse.class ).returnBundle( Bundle.class ).execute(); + } + + @Test( expected = AuthenticationException.class ) + public void searchQuestionnaireResponseInvalidAuthorization() throws Exception + { + expectProgramStageMetadataRequests(); + userDhis2Server.expect( ExpectedCount.once(), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6aW52YWxpZF8x" ) ) + .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events.json?skipPaging=false&page=1&pageSize=10&ouMode=ACCESSIBLE&fields=deleted,event,orgUnit,program,enrollment,trackedEntityInstance,programStage,status,eventDate,dueDate," + + "coordinate,lastUpdated,dataValues%5BdataElement,value,providedElsewhere,lastUpdated,storedBy%5D" ) ) + .andRespond( withStatus( HttpStatus.UNAUTHORIZED ) ); + + final IGenericClient client = createGenericClient(); + client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "invalid_1" ) ); + client.search().forResource( QuestionnaireResponse.class ).returnBundle( Bundle.class ).execute(); + } + + @Test + public void searchQuestionnaireResponseRepeated() throws Exception + { + searchQuestionnaireResponse(); + searchQuestionnaireResponse(); + } + + private void searchQuestionnaireResponse() throws Exception + { + systemDhis2Server.reset(); + userDhis2Server.reset(); + + expectProgramStageMetadataRequests(); + userDhis2Server.expect( ExpectedCount.once(), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) ) + .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events.json?skipPaging=false&page=1&pageSize=10&ouMode=ACCESSIBLE&fields=deleted,event,orgUnit,program,enrollment,trackedEntityInstance,programStage,status,eventDate," + + "dueDate,coordinate,lastUpdated,dataValues%5BdataElement,value,providedElsewhere,lastUpdated,storedBy%5D" ) ) + .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-event-91-get.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); + + final IGenericClient client = createGenericClient(); + client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) ); + Bundle bundle = client.search().forResource( QuestionnaireResponse.class ).returnBundle( Bundle.class ).execute(); + Assert.assertEquals( 1, bundle.getEntry().size() ); + QuestionnaireResponse questionnaireResponse = (QuestionnaireResponse) bundle.getEntry().get( 0 ).getResource(); + Assert.assertEquals( "Patient/JeR2Ul4mZfx", questionnaireResponse.getSubject().getReference() ); + Assert.assertEquals( "Location/ldXIdLNUNEn", + Objects.requireNonNull( LocationExtensionUtils.getValue( questionnaireResponse ) ).getReferenceElement().getValue() ); + + systemDhis2Server.verify(); + userDhis2Server.verify(); + } + + @Test + public void searchQuestionnaireResponsePatient() throws Exception + { + expectProgramStageMetadataRequests(); + userDhis2Server.expect( ExpectedCount.once(), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) ) + .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events.json?trackedEntityInstance=JeR2Ul4mZfx&skipPaging=false&page=1&pageSize=10&ouMode=ACCESSIBLE&fields=deleted,event,orgUnit,program,enrollment," + + "trackedEntityInstance,programStage,status,eventDate,dueDate,coordinate,lastUpdated,dataValues%5BdataElement,value,providedElsewhere,lastUpdated,storedBy%5D" ) ) + .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-event-91-get.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); + + final IGenericClient client = createGenericClient(); + client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) ); + Bundle bundle = client.search().forResource( QuestionnaireResponse.class ).where( QuestionnaireResponse.PATIENT.hasId( new IdType( "Patient", "JeR2Ul4mZfx" ) ) ).returnBundle( Bundle.class ).execute(); + Assert.assertEquals( 1, bundle.getEntry().size() ); + QuestionnaireResponse questionnaireResponse = (QuestionnaireResponse) bundle.getEntry().get( 0 ).getResource(); + Assert.assertEquals( "Patient/JeR2Ul4mZfx", questionnaireResponse.getSubject().getReference() ); + Assert.assertEquals( "Location/ldXIdLNUNEn", + Objects.requireNonNull( LocationExtensionUtils.getValue( questionnaireResponse ) ).getReferenceElement().getValue() ); + + systemDhis2Server.verify(); + userDhis2Server.verify(); + } + + @Test( expected = AuthenticationException.class ) + public void createQuestionnaireResponseWithoutAuthorization() throws Exception + { + expectProgramStageMetadataRequests(); + + QuestionnaireResponse questionnaireResponse = (QuestionnaireResponse) getFhirContext().newJsonParser().parseResource( + IOUtils.resourceToString( "/org/dhis2/fhir/adapter/fhir/test/" + getResourceDir() + "/get-questionnaire-response-91.json", StandardCharsets.UTF_8 ) ); + questionnaireResponse.setId( (IdType) null ); + questionnaireResponse.setSubject( new Reference( "Patient/JeR2Ul4mZfx" ) ); + + final IGenericClient client = createGenericClient(); + client.create().resource( questionnaireResponse ).execute(); + } + + @Test( expected = AuthenticationException.class ) + public void createQuestionnaireResponseInvalidAuthorization() throws Exception + { + expectProgramStageMetadataRequests(); + userDhis2Server.expect( ExpectedCount.once(), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events.json?strategy=CREATE" ) ).andExpect( method( HttpMethod.POST ) ) + .andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6aW52YWxpZF8x" ) ) + .andExpect( content().contentTypeCompatibleWith( MediaType.APPLICATION_JSON ) ) + .andExpect( content().json( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-event-91-create.json", StandardCharsets.UTF_8 ) ) ) + .andRespond( withStatus( HttpStatus.UNAUTHORIZED ) ); + + QuestionnaireResponse questionnaireResponse = (QuestionnaireResponse) getFhirContext().newJsonParser().parseResource( + IOUtils.resourceToString( "/org/dhis2/fhir/adapter/fhir/test/" + getResourceDir() + "/get-questionnaire-response-91.json", StandardCharsets.UTF_8 ) ); + questionnaireResponse.setId( (IdType) null ); + questionnaireResponse.setSubject( new Reference( "Patient/JeR2Ul4mZfx" ) ); + LocationExtensionUtils.setValue( questionnaireResponse, new Reference( "Location/ldXIdLNUNEn" ) ); + + final IGenericClient client = createGenericClient(); + client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "invalid_1" ) ); + client.create().resource( questionnaireResponse ).execute(); + } + + @Test + public void createQuestionnaireResponse() throws Exception + { + expectProgramStageMetadataRequests(); + userDhis2Server.expect( ExpectedCount.once(), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events.json?strategy=CREATE" ) ).andExpect( method( HttpMethod.POST ) ) + .andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) ) + .andExpect( content().contentTypeCompatibleWith( MediaType.APPLICATION_JSON ) ) + .andExpect( content().json( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-event-91-create.json", StandardCharsets.UTF_8 ) ) ) + .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-event-91-create-response.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) + .headers( createDefaultHeaders() ) ); + + QuestionnaireResponse questionnaireResponse = (QuestionnaireResponse) getFhirContext().newJsonParser().parseResource( + IOUtils.resourceToString( "/org/dhis2/fhir/adapter/fhir/test/" + getResourceDir() + "/get-questionnaire-response-91.json", StandardCharsets.UTF_8 ) ); + questionnaireResponse.setId( (IdType) null ); + questionnaireResponse.setSubject( new Reference( "Patient/JeR2Ul4mZfx" ) ); + LocationExtensionUtils.setValue( questionnaireResponse, new Reference( "Location/ldXIdLNUNEn" ) ); + + final IGenericClient client = createGenericClient(); + client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) ); + MethodOutcome methodOutcome = client.create().resource( questionnaireResponse ).execute(); + Assert.assertEquals( Boolean.TRUE, methodOutcome.getCreated() ); + Assert.assertEquals( "http://localhost:" + localPort + "/fhir/r4/default/QuestionnaireResponse/deR4kl4mnf7", methodOutcome.getId().toString() ); + } + + @Test( expected = AuthenticationException.class ) + public void updateQuestionnaireResponseWithoutAuthorization() throws Exception + { + expectProgramStageMetadataRequests(); + userDhis2Server.expect( ExpectedCount.once(), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) ) + .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/trackedEntityInstances/JeR2Ul4mZfx.json?" + + "fields=deleted,trackedEntityInstance,trackedEntityType,orgUnit,coordinates,lastUpdated,attributes%5Battribute,value,lastUpdated,storedBy%5D" ) ) + .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-tei-15-get.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); + + QuestionnaireResponse questionnaireResponse = (QuestionnaireResponse) getFhirContext().newJsonParser().parseResource( + IOUtils.resourceToString( "/org/dhis2/fhir/adapter/fhir/test/" + getResourceDir() + "/get-questionnaire-response-91.json", StandardCharsets.UTF_8 ) ); + questionnaireResponse.setId( "deR4kl4mnf7" ); + questionnaireResponse.setSubject( new Reference( "Patient/JeR2Ul4mZfx" ) ); + + final IGenericClient client = createGenericClient(); + client.update().resource( questionnaireResponse ).execute(); + } + + @Test( expected = AuthenticationException.class ) + public void updateQuestionnaireResponseInvalidAuthorization() throws Exception + { + expectProgramStageMetadataRequests(); + userDhis2Server.expect( ExpectedCount.between( 1, 2 ), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6aW52YWxpZF8x" ) ) + .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events/deR4kl4mnf7.json?fields=deleted,event,orgUnit,program,enrollment,trackedEntityInstance,programStage,status,eventDate,dueDate,coordinate,lastUpdated," + + "dataValues%5BdataElement,value,providedElsewhere,lastUpdated,storedBy%5D" ) ) + .andRespond( withStatus( HttpStatus.UNAUTHORIZED ) ); + + QuestionnaireResponse questionnaireResponse = (QuestionnaireResponse) getFhirContext().newJsonParser().parseResource( + IOUtils.resourceToString( "/org/dhis2/fhir/adapter/fhir/test/" + getResourceDir() + "/get-questionnaire-response-91.json", StandardCharsets.UTF_8 ) ); + questionnaireResponse.setId( "deR4kl4mnf7" ); + questionnaireResponse.setSubject( new Reference( "Patient/JeR2Ul4mZfx" ) ); + + final IGenericClient client = createGenericClient(); + client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "invalid_1" ) ); + client.update().resource( questionnaireResponse ).execute(); + } + + @Test + public void updateQuestionnaireResponse() throws Exception + { + expectProgramStageMetadataRequests(); + + userDhis2Server.expect( ExpectedCount.between( 1, 3 ), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events/deR4kl4mnf7.json?fields=deleted,event,orgUnit,program,enrollment,trackedEntityInstance,programStage,status,eventDate," + + "dueDate,coordinate,lastUpdated,dataValues%5BdataElement,value,providedElsewhere,lastUpdated,storedBy%5D" ) ) + .andExpect( method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) ) + .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-event-91-get.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); + userDhis2Server.expect( ExpectedCount.once(), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events/deR4kl4mnf7.json?mergeMode=MERGE" ) ).andExpect( method( HttpMethod.PUT ) ) + .andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) ) + .andExpect( content().contentTypeCompatibleWith( MediaType.APPLICATION_JSON ) ) + .andExpect( content().json( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-event-91-update.json", StandardCharsets.UTF_8 ) ) ) + .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-event-91-update-response.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) + .headers( createDefaultHeaders() ) ); + + QuestionnaireResponse questionnaireResponse = (QuestionnaireResponse) getFhirContext().newJsonParser().parseResource( + IOUtils.resourceToString( "/org/dhis2/fhir/adapter/fhir/test/" + getResourceDir() + "/get-questionnaire-response-91.json", StandardCharsets.UTF_8 ) ); + questionnaireResponse.setId( "deR4kl4mnf7" ); + questionnaireResponse.setSubject( new Reference( "Patient/JeR2Ul4mZfx" ) ); + questionnaireResponse.setStatus( QuestionnaireResponse.QuestionnaireResponseStatus.INPROGRESS ); + LocationExtensionUtils.setValue( questionnaireResponse, new Reference( "Location/ldXIdLNUNEn" ) ); + EventStatusExtensionUtils.setValue( questionnaireResponse, EventStatus.OVERDUE, ResourceFactory::createType ); + DueDateExtensionUtils.setValue( questionnaireResponse, + Date.from( LocalDate.of( 2018, 11, 14 ).atStartOfDay( ZoneId.systemDefault() ).toInstant() ), ResourceFactory::createType ); + + final IGenericClient client = createGenericClient(); + client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) ); + MethodOutcome methodOutcome = client.update().resource( questionnaireResponse ).execute(); + Assert.assertNotEquals( Boolean.TRUE, methodOutcome.getCreated() ); + Assert.assertEquals( "http://localhost:" + localPort + "/fhir/r4/default/QuestionnaireResponse/deR4kl4mnf7", methodOutcome.getId().toString() ); + } + + @Test( expected = AuthenticationException.class ) + public void deleteQuestionnaireResponseWithoutAuthorization() throws Exception + { + expectProgramStageMetadataRequests(); + + final IGenericClient client = createGenericClient(); + client.delete().resourceById( "QuestionnaireResponse", "deR4kl4mnf7" ).execute(); + } + + @Test( expected = AuthenticationException.class ) + public void deleteQuestionnaireResponseInvalidAuthorization() throws Exception + { + expectProgramStageMetadataRequests(); + userDhis2Server.expect( ExpectedCount.once(), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events/deR4kl4mnf7" ) ) + .andExpect( method( HttpMethod.DELETE ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6aW52YWxpZF8x" ) ) + .andRespond( withStatus( HttpStatus.UNAUTHORIZED ) ); + + final IGenericClient client = createGenericClient(); + client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "invalid_1" ) ); + client.delete().resourceById( "QuestionnaireResponse", "deR4kl4mnf7" ).execute(); + + userDhis2Server.verify(); + } + + @Test + public void deleteQuestionnaireResponse() throws Exception + { + expectProgramStageMetadataRequests(); + userDhis2Server.expect( ExpectedCount.once(), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events/deR4kl4mnf7" ) ) + .andExpect( method( HttpMethod.DELETE ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) ) + .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-event-91-get.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); + + final IGenericClient client = createGenericClient(); + client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) ); + client.delete().resourceById( "QuestionnaireResponse", "deR4kl4mnf7" ).execute(); + + userDhis2Server.verify(); + } +} diff --git a/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-event-91-get.json b/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-event-91-get.json new file mode 100644 index 00000000..104fb831 --- /dev/null +++ b/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-event-91-get.json @@ -0,0 +1,27 @@ +{ + "events": [ + { + "event": "deR4kl4mnf7", + "status": "ACTIVE", + "eventDate": "2018-11-10T00:00:00+01:00", + "dueDate": "2018-11-12T00:00:00+01:00", + "coordinate": null, + "dataValues": [ + { + "value": "3666", + "providedElsewhere": false, + "dataElement": "BnplxU2jGvX" + }, + { + "value": "1", + "providedElsewhere": false, + "dataElement": "ft7iD5ZzPxJ" + } + ], + "orgUnit": "ldXIdLNUNEn", + "program": "EPDyQuoRnXk", + "trackedEntityInstance": "JeR2Ul4mZfx", + "programStage": "MsWxkiY6tMS" + } + ] +} \ No newline at end of file diff --git a/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-event-91-update-response.json b/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-event-91-update-response.json new file mode 100644 index 00000000..fb4ea45f --- /dev/null +++ b/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-event-91-update-response.json @@ -0,0 +1,11 @@ +{ + "status": "OK", + "response": { + "importSummaries": [ + { + "status": "SUCCESS", + "reference": "deR4kl4mnf7" + } + ] + } +} diff --git a/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-event-91-update.json b/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-event-91-update.json new file mode 100644 index 00000000..121dc860 --- /dev/null +++ b/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-event-91-update.json @@ -0,0 +1,22 @@ +{ + "status": "OVERDUE", + "eventDate": "2018-11-10T00:00:00+01:00", + "dueDate": "2018-11-14T00:00:00+01:00", + "coordinate": null, + "dataValues": [ + { + "value": "3666", + "providedElsewhere": false, + "dataElement": "BnplxU2jGvX" + }, + { + "value": "1", + "providedElsewhere": false, + "dataElement": "ft7iD5ZzPxJ" + } + ], + "orgUnit": "ldXIdLNUNEn", + "program": "EPDyQuoRnXk", + "trackedEntityInstance": "JeR2Ul4mZfx", + "programStage": "MsWxkiY6tMS" +} \ No newline at end of file diff --git a/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/single-event-91-get.json b/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/single-event-91-get.json new file mode 100644 index 00000000..2529d67a --- /dev/null +++ b/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/single-event-91-get.json @@ -0,0 +1,23 @@ +{ + "event": "deR4kl4mnf7", + "status": "ACTIVE", + "eventDate": "2018-11-10T00:00:00+01:00", + "dueDate": "2018-11-12T00:00:00+01:00", + "coordinate": null, + "dataValues": [ + { + "value": "3666", + "providedElsewhere": false, + "dataElement": "BnplxU2jGvX" + }, + { + "value": "1", + "providedElsewhere": false, + "dataElement": "ft7iD5ZzPxJ" + } + ], + "orgUnit": "ldXIdLNUNEn", + "program": "EPDyQuoRnXk", + "trackedEntityInstance": "JeR2Ul4mZfx", + "programStage": "MsWxkiY6tMS" +} \ No newline at end of file diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/ProgramStageRule.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/ProgramStageRule.java index f7045bbb..80823bb9 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/ProgramStageRule.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/ProgramStageRule.java @@ -64,12 +64,12 @@ query = "SELECT psr FROM ProgramStageRule psr " + "LEFT JOIN psr.programStage ps ON (ps.enabled=true AND ps.expEnabled=true AND (ps.fhirCreateEnabled=true OR ps.fhirUpdateEnabled=true) AND ps.programStageReference IN (:programStageReferences)) " + "LEFT JOIN ps.program p ON (p.enabled=true AND p.expEnabled=true AND (p.fhirCreateEnabled=true OR p.fhirUpdateEnabled=true) AND p.programReference IN (:programReferences)) WHERE " + - "psr.enabled=true AND psr.expEnabled=true AND (psr.fhirCreateEnabled=true OR psr.fhirUpdateEnabled=true) AND psr.transformExpScript IS NOT NULL" ), + "psr.enabled=true AND psr.expEnabled=true AND (psr.fhirCreateEnabled=true OR psr.fhirUpdateEnabled=true)" ), @NamedQuery( name = ProgramStageRule.FIND_ALL_EXP_BY_DATA_REF_NAMED_QUERY, query = "SELECT psr FROM ProgramStageRule psr " + "LEFT JOIN psr.programStage ps ON (ps.enabled=true AND ps.expEnabled=true AND (ps.fhirCreateEnabled=true OR ps.fhirUpdateEnabled=true) AND ps.programStageReference IN (:programStageReferences)) " + "LEFT JOIN ps.program p ON (p.enabled=true AND p.expEnabled=true AND (p.fhirCreateEnabled=true OR p.fhirUpdateEnabled=true) AND p.programReference IN (:programReferences)) WHERE " + - "psr.enabled=true AND psr.expEnabled=true AND (psr.fhirCreateEnabled=true OR psr.fhirUpdateEnabled=true) AND psr.transformExpScript IS NOT NULL AND " + + "psr.enabled=true AND psr.expEnabled=true AND (psr.fhirCreateEnabled=true OR psr.fhirUpdateEnabled=true) AND " + "EXISTS (SELECT 1 FROM RuleDhisDataReference edr WHERE edr.rule=psr AND edr.dataReference IN (:dataReferences))" ) } ) @Relation( value = "rule", collectionRelation = "rules" ) diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/CustomRuleRepository.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/CustomRuleRepository.java index f1b83c57..a3ddefad 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/CustomRuleRepository.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/CustomRuleRepository.java @@ -68,5 +68,4 @@ public interface CustomRuleRepository @RestResource( exported = false ) @Nonnull Collection> findAllExp( @Nonnull DhisResourceType dhisResourceType ); - } diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/impl/CustomRuleRepositoryImpl.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/impl/CustomRuleRepositoryImpl.java index 5f070628..baae592e 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/impl/CustomRuleRepositoryImpl.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/impl/CustomRuleRepositoryImpl.java @@ -120,6 +120,25 @@ public Collection> findAllExp( @Nonnull DhisRes return rules.stream().map( r -> { Hibernate.initialize( r.getDhisDataReferences() ); + + return new RuleInfo<>( r, r.getDhisDataReferences() ); + } ).collect( Collectors.toList() ); + } + + @RestResource( exported = false ) + @Nonnull + @Cacheable( key = "{#root.methodName, #a0, #a1}", cacheManager = "metadataCacheManager", cacheNames = "rule" ) + @Transactional( readOnly = true ) + public Collection> findAllExp( @Nonnull DhisResourceType dhisResourceType, @Nonnull FhirResourceType fhirResourceType ) + { + final List rules = entityManager.createQuery( "SELECT r FROM " + dhisResourceType.getRuleType() + + " r WHERE r.enabled=true AND r.expEnabled=true AND r.fhirResourceType=:fhirResourceType AND " + + "(r.fhirCreateEnabled=true OR r.fhirUpdateEnabled=true)", AbstractRule.class ) + .setParameter( "fhirResourceType", fhirResourceType ).getResultList(); + + return rules.stream().map( r -> { + Hibernate.initialize( r.getDhisDataReferences() ); + return new RuleInfo<>( r, r.getDhisDataReferences() ); } ).collect( Collectors.toList() ); } diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/DhisToFhirRequestResolver.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/DhisToFhirRequestResolver.java index ee7d7494..bad1109e 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/DhisToFhirRequestResolver.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/DhisToFhirRequestResolver.java @@ -58,7 +58,7 @@ public interface DhisToFhirRequestResolver List> resolveRules( @Nonnull ScriptedDhisResource dhisResource ); @Nonnull - List> resolveRules( @Nonnull ScriptedDhisResource dhisResource, @Nonnull List> rules ); + List> filterRules( @Nonnull ScriptedDhisResource dhisResource, @Nonnull List> rules ); @Nonnull Optional resolveFhirClient( @Nonnull ScriptedDhisResource scriptedDhisResource ); diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/DhisToFhirTransformerServiceImpl.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/DhisToFhirTransformerServiceImpl.java index 45da1791..4edb03a3 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/DhisToFhirTransformerServiceImpl.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/DhisToFhirTransformerServiceImpl.java @@ -318,8 +318,8 @@ public DhisToFhirTransformerRequest createTransformerRequest( @Nonnull FhirClien { final DhisToFhirRequestResolver requestResolver = getRequestResolver( dhisRequest.getResourceType() ); - return createTransformerRequest( dhisRequest, rr -> rr.convert( resource, dhisRequest ), requestResolver, ( rr, scriptedResource ) -> rr.resolveRules( scriptedResource, rules ), - ri -> true, ( si, rr ) -> fhirClient ); + return createTransformerRequest( dhisRequest, rr -> rr.convert( resource, dhisRequest ), requestResolver, + ( rr, scriptedResource ) -> rr.filterRules( scriptedResource, rules ), ri -> true, ( si, rr ) -> fhirClient ); } @Nullable diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/enrollment/EnrollmentToFhirRequestResolver.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/enrollment/EnrollmentToFhirRequestResolver.java index a65af7a7..b540bbe7 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/enrollment/EnrollmentToFhirRequestResolver.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/enrollment/EnrollmentToFhirRequestResolver.java @@ -118,7 +118,7 @@ public List> resolveRules( @Nonnull ScriptedDhi @Nonnull @Override - public List> resolveRules( @Nonnull ScriptedDhisResource dhisResource, @Nonnull List> rules ) + public List> filterRules( @Nonnull ScriptedDhisResource dhisResource, @Nonnull List> rules ) { return rules.stream().map( ri -> new RuleInfo<>( (EnrollmentRule) ri.getRule(), ri.getDhisDataReferences() ) ) .sorted().collect( Collectors.toList() ); diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/AbstractDhisMetadataToFhirRequestResolver.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/AbstractDhisMetadataToFhirRequestResolver.java index 574e8695..c1ad7e0c 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/AbstractDhisMetadataToFhirRequestResolver.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/AbstractDhisMetadataToFhirRequestResolver.java @@ -61,12 +61,13 @@ protected AbstractDhisMetadataToFhirRequestResolver( @Nonnull FhirClientReposito @Override public List> resolveRules( @Nonnull ScriptedDhisResource dhisResource ) { - return ruleRepository.findAllExp( dhisResource.getResourceType() ).stream().sorted().collect( Collectors.toList() ); + return ruleRepository.findAllExp( dhisResource.getResourceType() ).stream() + .sorted().collect( Collectors.toList() ); } @Nonnull @Override - public List> resolveRules( @Nonnull ScriptedDhisResource dhisResource, @Nonnull List> rules ) + public List> filterRules( @Nonnull ScriptedDhisResource dhisResource, @Nonnull List> rules ) { return rules.stream().sorted().collect( Collectors.toList() ); } diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/program/ProgramStageToFhirRequestResolver.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/program/ProgramStageToFhirRequestResolver.java index 87f9d1ac..76ef7e10 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/program/ProgramStageToFhirRequestResolver.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/program/ProgramStageToFhirRequestResolver.java @@ -74,7 +74,7 @@ public class ProgramStageToFhirRequestResolver extends AbstractDhisToFhirRequest { private final ProgramMetadataService programMetadataService; - private final ProgramStageRuleRepository ruleRepository; + private final ProgramStageRuleRepository programStageRuleRepository; private final TrackedEntityService trackedEntityService; @@ -87,7 +87,7 @@ public class ProgramStageToFhirRequestResolver extends AbstractDhisToFhirRequest public ProgramStageToFhirRequestResolver( @Nonnull FhirClientRepository fhirClientRepository, @Nonnull ProgramMetadataService programMetadataService, - @Nonnull ProgramStageRuleRepository ruleRepository, + @Nonnull ProgramStageRuleRepository programStageRuleRepository, @Nonnull TrackedEntityService trackedEntityService, @Nonnull TrackedEntityMetadataService trackedEntityMetadataService, @Nonnull ScriptExecutionContext scriptExecutionContext, @@ -96,7 +96,7 @@ public ProgramStageToFhirRequestResolver( super( fhirClientRepository ); this.programMetadataService = programMetadataService; - this.ruleRepository = ruleRepository; + this.programStageRuleRepository = programStageRuleRepository; this.trackedEntityService = trackedEntityService; this.trackedEntityMetadataService = trackedEntityMetadataService; this.scriptExecutionContext = scriptExecutionContext; @@ -116,13 +116,13 @@ public List> resolveRules( @Nonnull ScriptedDhi { final ScriptedEvent event = (ScriptedEvent) dhisResource; - return ruleRepository.findAllExp( event.getProgram().getAllReferences(), event.getProgramStage().getAllReferences(), null ) + return programStageRuleRepository.findAllExp( event.getProgram().getAllReferences(), event.getProgramStage().getAllReferences(), null ) .stream().sorted().collect( Collectors.toList() ); } @Nonnull @Override - public List> resolveRules( @Nonnull ScriptedDhisResource dhisResource, @Nonnull List> rules ) + public List> filterRules( @Nonnull ScriptedDhisResource dhisResource, @Nonnull List> rules ) { final ScriptedEvent event = (ScriptedEvent) dhisResource; final Program program = event.getProgram(); diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/trackedentity/TrackedEntityToFhirRequestResolver.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/trackedentity/TrackedEntityToFhirRequestResolver.java index d4a5142c..06be8698 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/trackedentity/TrackedEntityToFhirRequestResolver.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/trackedentity/TrackedEntityToFhirRequestResolver.java @@ -108,7 +108,7 @@ public List> resolveRules( @Nonnull ScriptedDhi @Nonnull @Override - public List> resolveRules( @Nonnull ScriptedDhisResource dhisResource, @Nonnull List> rules ) + public List> filterRules( @Nonnull ScriptedDhisResource dhisResource, @Nonnull List> rules ) { final ScriptedTrackedEntityInstance tei = (ScriptedTrackedEntityInstance) dhisResource; final TrackedEntityType type = tei.getType();