Skip to content

Commit

Permalink
Adds support reading FHIR QuestionnaireResponse.
Browse files Browse the repository at this point in the history
Tests are still missing.
  • Loading branch information
volsch committed Aug 18, 2019
1 parent dfb4de6 commit 80712f4
Show file tree
Hide file tree
Showing 40 changed files with 1,015 additions and 85 deletions.
47 changes: 47 additions & 0 deletions app/src/test/java/org/dhis2/fhir/adapter/AbstractAppTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,14 @@
import org.apache.activemq.artemis.jms.client.ActiveMQSession;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.dhis2.fhir.adapter.dhis.model.DhisResourceId;
import org.dhis2.fhir.adapter.fhir.data.repository.FhirDhisAssignmentRepository;
import org.dhis2.fhir.adapter.fhir.metadata.model.FhirResourceType;
import org.dhis2.fhir.adapter.fhir.metadata.repository.FhirClientRepository;
import org.dhis2.fhir.adapter.fhir.metadata.repository.RuleRepository;
import org.dhis2.fhir.adapter.fhir.model.FhirVersion;
import org.dhis2.fhir.adapter.fhir.security.AdapterSystemAuthenticationToken;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.Assert;
import org.junit.Before;
import org.junit.runner.RunWith;
Expand All @@ -59,6 +65,8 @@
import org.springframework.http.MediaType;
import org.springframework.jms.UncategorizedJmsException;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.test.context.TestSecurityContextHolder;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.client.MockRestServiceServer;
Expand All @@ -74,6 +82,7 @@
import javax.persistence.EntityManager;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.UUID;

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
Expand Down Expand Up @@ -173,6 +182,15 @@ public abstract class AbstractAppTest
@Autowired
protected PlatformTransactionManager transactionManager;

@Autowired
protected FhirDhisAssignmentRepository assignmentRepository;

@Autowired
protected RuleRepository ruleRepository;

@Autowired
protected FhirClientRepository fhirClientRepository;

private long resourceDlQueueCount;

@Nonnull
Expand Down Expand Up @@ -250,9 +268,33 @@ protected HttpHeaders createDefaultHeaders()
{
final HttpHeaders headers = new HttpHeaders();
headers.setDate( System.currentTimeMillis() );

return headers;
}

protected void createAssignment( @Nonnull UUID ruleId, @Nonnull UUID fhirClientId, @Nonnull DhisResourceId dhisResourceId, @Nonnull IIdType fhirResourceId )
{
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
SecurityContextHolder.getContext().setAuthentication( new AdapterSystemAuthenticationToken() );
try
{
assignmentRepository.saveFhirResourceId(
ruleRepository.findById( ruleId ).orElseGet( () -> {
Assert.fail( "Rule could not be found: " + ruleId );
return null;
} ),
fhirClientRepository.findById( fhirClientId ).orElseGet( () -> {
Assert.fail( "FHIR client could not be found: " + fhirClientId );
return null;
} ),
dhisResourceId, fhirResourceId );
}
finally
{
SecurityContextHolder.getContext().setAuthentication( authentication );
}
}

protected void notifyResource( @Nonnull FhirResourceType resourceType, @Nullable String resourceSearchResponse,
@Nullable String resourceId, @Nullable String resourceResponse, boolean payload ) throws Exception
{
Expand All @@ -261,6 +303,7 @@ protected void notifyResource( @Nonnull FhirResourceType resourceType, @Nullable
fhirMockServer.removeStub( previousResourceSearchStubMapping );
previousResourceSearchStubMapping = null;
}

if ( StringUtils.isNotBlank( resourceSearchResponse ) )
{
final UrlPattern urlPattern = urlMatching( getBaseFhirContext() +
Expand All @@ -271,6 +314,7 @@ protected void notifyResource( @Nonnull FhirResourceType resourceType, @Nullable
.withHeader( "Content-Type", "application/fhir+json" )
.withBody( resourceSearchResponse ) ) );
}

if ( StringUtils.isNotBlank( resourceId ) && StringUtils.isNotBlank( resourceResponse ) )
{
fhirMockServer.stubFor( WireMock.get( urlEqualTo( getBaseFhirContext() +
Expand Down Expand Up @@ -306,16 +350,19 @@ protected void waitForEmptyResourceQueue() throws Exception
{
messageCount = getQueueMessageCount( fhirRestHookRequestQueueJmsTemplate, null ) +
getQueueMessageCount( fhirResourceQueueJmsTemplate, null );

if ( messageCount > 0 )
{
if ( (System.currentTimeMillis() - begin) > MAX_COMPLETED_POLL_TIME )
{
Assert.fail( "Waited more than " + MAX_COMPLETED_POLL_TIME + " ms, but there are still " + messageCount + " messages in the queues." );
}

Thread.sleep( 100L );
}
}
while ( messageCount > 0 );

Assert.assertEquals( "Resource dead letter queue contains messages.",
resourceDlQueueCount, getQueueMessageCount( fhirResourceQueueJmsTemplate, RESOURCE_DL_QUEUE_NAME ) );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,9 @@ protected void expectMetadataRequests() throws Exception
{
systemDhis2Server.expect( ExpectedCount.between( 0, 1 ), method( HttpMethod.GET ) ).andExpect( header( "Authorization", testConfiguration.getDhis2SystemAuthorization() ) )
.andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programs.json?paging=false&fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration," +
"withoutRegistration," +
"captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,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" ) )
"withoutRegistration,captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid," +
"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/all-programs.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 + "/trackedEntityTypes/MCPQUTHX1Ze.json?fields=id,name,trackedEntityTypeAttributes%5Bid,name,valueType,mandatory,trackedEntityAttribute%5Bid,name,code,valueType,generated," +
Expand All @@ -73,10 +69,9 @@ protected void expectMetadataRequests() throws Exception
systemDhis2Server.expect( ExpectedCount.between( 0, 1 ), method( HttpMethod.GET ) ).andExpect( header( "Authorization", testConfiguration.getDhis2SystemAuthorization() ) )
.andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programs.json?paging=false&" +
"fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration,captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid," +
"name,valueType," +
"mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart," +
"programStageDataElements%5Bid,compulsory," +
"allowProvidedElsewhere,dataElement%5Bid,name,code,description,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D%5D&filter=name:eq:Child%20Programme" ) )
"name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate," +
"minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,description,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/single-program.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,20 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import ca.uhn.fhir.model.primitive.IdDt;
import com.github.tomakehurst.wiremock.client.WireMock;
import org.apache.commons.io.IOUtils;
import org.dhis2.fhir.adapter.dhis.model.DhisResourceId;
import org.dhis2.fhir.adapter.dhis.model.DhisResourceType;
import org.dhis2.fhir.adapter.fhir.metadata.model.FhirResourceType;
import org.dhis2.fhir.adapter.fhir.model.FhirVersion;
import org.junit.Test;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.test.web.client.ExpectedCount;

import java.nio.charset.StandardCharsets;
import java.util.UUID;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
Expand All @@ -52,8 +57,11 @@ public abstract class AbstractQuestionnaireResponseToProgramStageTransformationA
extends AbstractProgramStageTransformationAppTest
{
@Test
public void createEnrollment() throws Exception
public void createQuestionnaireResponse() throws Exception
{
createAssignment( UUID.fromString( "c4e17e7d-880e-45b5-9bc5-568da8c79742" ), testConfiguration.getFhirClientId( FhirVersion.R4 ),
new DhisResourceId( DhisResourceType.ENROLLMENT, "ieR4nl4muff" ), new IdDt( "CarePlan", "90" ) );

expectMetadataRequests();
fhirMockServer.stubFor( WireMock.get( urlPathEqualTo( getBaseFhirContext() + "/Patient/15" ) ).willReturn( aResponse()
.withHeader( "Content-Type", "application/fhir+json" )
Expand All @@ -62,27 +70,30 @@ public void createEnrollment() throws Exception
.withHeader( "Content-Type", "application/fhir+json" )
.withBody( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/fhir/test/" + getResourceDir() + "/get-organization-20.json", StandardCharsets.UTF_8 ) ) ) );

systemDhis2Server.expect( ExpectedCount.once(), 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 ) );
systemDhis2Server.expect( ExpectedCount.between( 0, 1 ), method( HttpMethod.GET ) ).andExpect( header( "Authorization", testConfiguration.getDhis2SystemAuthorization() ) )
.andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programs/EPDyQuoRnXk.json?fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration," +
"withoutRegistration,captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid," +
"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" ) )
.andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-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 + "/organisationUnits.json?paging=false&fields=lastUpdated,id,code,name,shortName,displayName,level,openingDate,closedDate,coordinates,leaf,parent%5Bid%5D&filter=code:eq:OU_1357" ) )
.andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-org-unit-OU_1357.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) );
.andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/organisationUnits/ldXIdLNUNEn.json?fields=lastUpdated,id,code,name,shortName,displayName,level,openingDate,closedDate,coordinates,leaf,parent%5Bid%5D" ) )
.andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-org-unit-OU_1234.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) );

userDhis2Server.expect( ExpectedCount.once(), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/trackedEntityInstances.json?trackedEntityType=MCPQUTHX1Ze&ouMode=ACCESSIBLE&filter=jD1NGmSntCt:EQ:PT_88589&pageSize=2&fields=" +
"deleted,trackedEntityInstance,trackedEntityType,orgUnit,coordinates,lastUpdated,attributes%5Battribute,value,lastUpdated,storedBy%5D" ) )
.andExpect( method( HttpMethod.GET ) ).andExpect( header( "Authorization", testConfiguration.getDhis2UserAuthorization() ) )
.andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-tei-15-get.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 + "/organisationUnits/ldXIdLNUNEn.json?fields=lastUpdated,id,code,name,shortName,displayName,level,openingDate,closedDate,coordinates,leaf,parent%5Bid%5D" ) )
.andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-org-unit-OU_1234.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) );

userDhis2Server.expect( ExpectedCount.between( 2, 4 ), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/enrollments.json?program=EPDyQuoRnXk&programStatus=ACTIVE&trackedEntityInstance=JeR2Ul4mZfx&ouMode=ACCESSIBLE&fields=:all&" +
"order=lastUpdated:desc&pageSize=1" ) ).andExpect( method( HttpMethod.GET ) ).andExpect( header( "Authorization", testConfiguration.getDhis2UserAuthorization() ) )
.andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-enrollment-empty.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) );
userDhis2Server.expect( ExpectedCount.once(), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/enrollments.json?strategy=CREATE" ) ).andExpect( method( HttpMethod.POST ) )
userDhis2Server.expect( ExpectedCount.once(), requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/events.json?strategy=CREATE" ) ).andExpect( method( HttpMethod.POST ) )
.andExpect( header( "Authorization", testConfiguration.getDhis2UserAuthorization() ) )
.andExpect( content().contentTypeCompatibleWith( MediaType.APPLICATION_JSON ) )
.andExpect( content().json( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-enrollment-91-create.json", StandardCharsets.UTF_8 ) ) )
.andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-enrollment-91-create-response.json", StandardCharsets.UTF_8 ), 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() ) );

notifyResource( FhirResourceType.QUESTIONNAIRE_RESPONSE, null,
Expand Down
5 changes: 0 additions & 5 deletions app/src/test/resources/data.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2682,11 +2682,6 @@ imp_enrollment_org_lookup_script_id, imp_enrollment_date_lookup_script_id)
VALUES('417d0db376bc48bebc4223e7a7e663b0', 0, 'QUESTIONNAIRE_RESPONSE', 'PATIENT', '762b4137a98b4b10a0f5629d93e23461', '25a97bb47b394ed48677db4bcaa28ccf', '521b3a008ecc487ba7e3fe12b68e388a', '385e52d28674403db42586b5d4e9faf0',
'25a97bb47b394ed48677db4bcaa28ccf', '521b3a008ecc487ba7e3fe12b68e388a');

INSERT INTO fhir_rule (id, version, name, description, enabled, evaluation_order, fhir_resource_type, dhis_resource_type, transform_imp_script_id, exp_enabled, fhir_create_enabled, fhir_update_enabled, fhir_delete_enabled)
VALUES ('e113ec6ec61048aa9df2cf7739f40985', 0, 'Child Programme Birth Stage Questionnaire Response', NULL, TRUE, 0, 'QUESTIONNAIRE_RESPONSE', 'PROGRAM_STAGE_EVENT', '2d5ec1318fbc44d395c52544f7ff284f', TRUE, TRUE, TRUE, TRUE);
INSERT INTO fhir_program_stage_rule (id, program_stage_id, enrollment_creation_enabled,event_creation_enabled)
VALUES ('e113ec6ec61048aa9df2cf7739f40985','4c074c85be494b9d89739e16b9615dad', TRUE, TRUE);

-- Tracker Program Child Programme, Birth: OPV Dose
INSERT INTO fhir_rule_dhis_data_ref(id, version, rule_id, data_ref, script_arg_name, required)
SELECT 'e66efbcb7142445a8e1ad1ef524977c1', 0, id, 'CODE:DE_2006104', 'dataElement', true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"status": "OK",
"response": {
"importSummaries": [
{
"status": "SUCCESS",
"reference": "deR4kl4mnf7"
}
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"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"
}
Loading

0 comments on commit 80712f4

Please sign in to comment.