diff --git a/README.md b/README.md index d6d843c0..b1be2381 100644 --- a/README.md +++ b/README.md @@ -114,10 +114,6 @@ More changeable settings can be found in the file [default-application.yml](app/ ### Running The adapter WAR can be run with a servlet container 3.1 or later (like Apache Tomcat 8.5 or Jetty 9.3). - -After successfully building the application also Maven can be used to run the application. Enter the following command in folder app in the console: - - mvn jetty:run Since the created WAR file is an executable WAR file, also the following command can be entered in folder app/target in the console: diff --git a/app/pom.xml b/app/pom.xml index 48b0fc4b..29be64dc 100644 --- a/app/pom.xml +++ b/app/pom.xml @@ -126,21 +126,10 @@ maven-war-plugin - false + true - - org.eclipse.jetty - jetty-maven-plugin - 9.4.12.v20180830 - - - localhost - 8081 - - - @@ -155,6 +144,14 @@ org.springframework.boot spring-boot-maven-plugin + + + build-info + + build-info + + + diff --git a/app/src/test/java/org/dhis2/fhir/adapter/TestConfiguration.java b/app/src/test/java/org/dhis2/fhir/adapter/TestConfiguration.java index 5c48561b..c74fa483 100644 --- a/app/src/test/java/org/dhis2/fhir/adapter/TestConfiguration.java +++ b/app/src/test/java/org/dhis2/fhir/adapter/TestConfiguration.java @@ -35,6 +35,8 @@ import org.dhis2.fhir.adapter.fhir.security.SystemAuthenticationToken; import org.dhis2.fhir.adapter.lock.LockManager; import org.dhis2.fhir.adapter.lock.impl.EmbeddedLockManagerImpl; +import org.dhis2.fhir.adapter.script.ScriptCompiler; +import org.dhis2.fhir.adapter.script.impl.ScriptCompilerImpl; import org.dhis2.fhir.adapter.setup.Setup; import org.dhis2.fhir.adapter.setup.SetupResult; import org.dhis2.fhir.adapter.setup.SetupService; @@ -144,6 +146,13 @@ protected LockManager embeddedLockManager() return new EmbeddedLockManagerImpl(); } + @Nonnull + @Bean + protected ScriptCompiler scriptCompiler( @Value( "${dhis2.fhir-adapter.transformation.script-engine-name}" ) @Nonnull String scriptEngineName ) + { + return new ScriptCompilerImpl( scriptEngineName ); + } + @Nonnull @Bean protected WireMockServer fhirMockServer() diff --git a/app/src/test/java/org/dhis2/fhir/adapter/common/scriptabe/generator/JavaScriptGeneratorControllerAppTest.java b/app/src/test/java/org/dhis2/fhir/adapter/common/scriptabe/generator/JavaScriptGeneratorControllerAppTest.java index 93c1ac87..030a4ff5 100644 --- a/app/src/test/java/org/dhis2/fhir/adapter/common/scriptabe/generator/JavaScriptGeneratorControllerAppTest.java +++ b/app/src/test/java/org/dhis2/fhir/adapter/common/scriptabe/generator/JavaScriptGeneratorControllerAppTest.java @@ -29,8 +29,10 @@ */ import org.dhis2.fhir.adapter.AbstractAppTest; +import org.dhis2.fhir.adapter.script.ScriptCompiler; import org.hamcrest.Matchers; import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; import static org.hamcrest.Matchers.containsString; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; @@ -43,12 +45,16 @@ */ public class JavaScriptGeneratorControllerAppTest extends AbstractAppTest { + @Autowired + private ScriptCompiler scriptCompiler; + @Test public void scriptAvailable() throws Exception { - mockMvc.perform( get( "/scripts/to-dhis2-all-mapping.js" ) ) + final String script = mockMvc.perform( get( "/scripts/to-dhis2-all-mapping.js" ) ) .andExpect( status().isOk() ).andExpect( header().string( "Content-Type", Matchers.containsString( "application/javascript" ) ) ) .andExpect( content().string( containsString( "var trackedEntityInstance = new TrackedEntityInstance();" ) ) ) - .andExpect( content().string( containsString( "Copyright (c)" ) ) ); + .andExpect( content().string( containsString( "Copyright (c)" ) ) ).andReturn().getResponse().getContentAsString(); + scriptCompiler.compile( script ); } } diff --git a/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/JavaScriptGeneratorController.java b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/JavaScriptGeneratorController.java index 74e2a147..77c74042 100644 --- a/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/JavaScriptGeneratorController.java +++ b/common/src/main/java/org/dhis2/fhir/adapter/scriptable/generator/JavaScriptGeneratorController.java @@ -34,7 +34,8 @@ import org.dhis2.fhir.adapter.scriptable.ScriptMethod; import org.dhis2.fhir.adapter.scriptable.ScriptMethodArg; import org.dhis2.fhir.adapter.scriptable.ScriptType; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.io.ResourceLoader; @@ -48,6 +49,7 @@ import org.springframework.web.context.request.WebRequest; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import javax.annotation.PostConstruct; import java.io.IOException; import java.io.InputStreamReader; @@ -75,10 +77,11 @@ * * @author volsch */ -@ConditionalOnBean( JavaScriptGeneratorConfig.class ) @Controller public class JavaScriptGeneratorController { + private final Logger logger = LoggerFactory.getLogger( getClass() ); + public static final String LICENSE_FILE = "classpath:/dhis2-license.txt"; public static final String LINE_ENDING = "\r\n"; @@ -95,7 +98,7 @@ public class JavaScriptGeneratorController private String eTag; - public JavaScriptGeneratorController( @SuppressWarnings( "SpringJavaInjectionPointsAutowiringInspection" ) @Nonnull JavaScriptGeneratorConfig config, @Nonnull ResourceLoader resourceLoader ) + public JavaScriptGeneratorController( @Nullable JavaScriptGeneratorConfig config, @Nonnull ResourceLoader resourceLoader ) { this.config = config; this.resourceLoader = resourceLoader; @@ -104,6 +107,11 @@ public JavaScriptGeneratorController( @SuppressWarnings( "SpringJavaInjectionPoi @RequestMapping( path = "/scripts/to-dhis2-all-mapping.js", method = RequestMethod.GET, produces = "application/javascript;charset=UTF-8" ) public ResponseEntity getScript( @Nonnull WebRequest request ) { + if ( lastModified == null ) + { + return new ResponseEntity<>( HttpStatus.NOT_FOUND ); + } + if ( request.checkNotModified( eTag, lastModified.toEpochMilli() ) ) { return null; @@ -118,6 +126,12 @@ public ResponseEntity getScript( @Nonnull WebRequest request ) @PostConstruct protected void init() { + if ( config == null ) + { + logger.info( "JavaScript generator configuration could not be found. Generator is not available." ); + return; + } + lastModified = Instant.now(); final SortedMap> orderedClasses = new TreeMap<>(); diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/Script.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/Script.java index 8abd3c81..6aff1a51 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/Script.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/model/Script.java @@ -222,6 +222,7 @@ public void setVariables( SortedSet variables ) @OneToMany( mappedBy = "script", orphanRemoval = true, cascade = CascadeType.ALL ) @OrderBy( "id" ) + @JsonIgnore public List getSources() { return sources; diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/validator/AbstractBeforeCreateSaveRuleValidator.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/validator/AbstractBeforeCreateSaveRuleValidator.java index cd9b974f..8c90038a 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/validator/AbstractBeforeCreateSaveRuleValidator.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/validator/AbstractBeforeCreateSaveRuleValidator.java @@ -61,12 +61,17 @@ protected void validate( Object target, @Nonnull TransformDataType transformData { errors.rejectValue( "name", "AbstractRule.name.length", new Object[]{ AbstractRule.MAX_NAME_LENGTH }, "Name must not be longer than {0} characters." ); } + if ( rule.getTransformInScript() == null ) + { + errors.rejectValue( "transformInScript", "AbstractRule.transformInScript.null", "Transformation input script is mandatory." ); + } if ( rule.getFhirResourceType() == null ) { errors.rejectValue( "fhirResourceType", "AbstractRule.fhirResourceType.null", "FHIR resource type is mandatory." ); } else { + checkValidApplicableInScript( errors, "applicableInScript", rule.getFhirResourceType(), rule.getApplicableInScript() ); checkValidTransformInScript( errors, "transformInScript", rule.getFhirResourceType(), transformDataType, rule.getTransformInScript() ); } @@ -92,6 +97,26 @@ protected static void checkValidApplicableInScript( @NonNull Errors errors, @Non } } + protected static void checkValidTeiLookupScript( @NonNull Errors errors, @Nonnull String field, @Nonnull FhirResourceType fhirResourceType, @Nullable ExecutableScript executableScript ) + { + if ( executableScript == null ) + { + return; + } + if ( executableScript.getScript().getScriptType() != ScriptType.EVALUATE ) + { + errors.rejectValue( field, "AbstractRule." + field + ".scriptType", "Assigned script type for TEI evaluation must be EVALUATE." ); + } + if ( executableScript.getScript().getReturnType() != DataType.FHIR_RESOURCE ) + { + errors.rejectValue( field, "AbstractRule." + field + ".returnType", "Assigned return type for TEI evaluation script must be FHIR_RESOURCE." ); + } + if ( (executableScript.getScript().getInputType() != null) && (executableScript.getScript().getInputType().getFhirResourceType() != fhirResourceType) ) + { + errors.rejectValue( field, "AbstractRule." + field + ".inputType", new Object[]{ fhirResourceType }, "Assigned input type for TEI evaluation script must be the same as for the rule {0}." ); + } + } + protected static void checkValidTransformInScript( @NonNull Errors errors, @Nonnull String field, @Nonnull FhirResourceType fhirResourceType, @Nonnull TransformDataType transformDataType, @Nullable ExecutableScript executableScript ) { if ( executableScript == null ) diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/validator/BeforeCreateSaveTrackedEntityRuleValidator.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/validator/BeforeCreateSaveTrackedEntityRuleValidator.java index 6d0c08da..f4759f00 100644 --- a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/validator/BeforeCreateSaveTrackedEntityRuleValidator.java +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/metadata/repository/validator/BeforeCreateSaveTrackedEntityRuleValidator.java @@ -61,5 +61,6 @@ public void validate( Object target, @Nonnull Errors errors ) } BeforeCreateSaveFhirResourceMappingValidator.checkValidOrgLookupScript( errors, "TrackedEntityRule.", "orgUnitLookupScript", rule.getFhirResourceType(), rule.getOrgUnitLookupScript() ); BeforeCreateSaveFhirResourceMappingValidator.checkValidLocationLookupScript( errors, "TrackedEntityRule.", "locationLookupScript", rule.getFhirResourceType(), rule.getLocationLookupScript() ); + checkValidTeiLookupScript( errors, "teiLookupScript", rule.getFhirResourceType(), rule.getTeiLookupScript() ); } } diff --git a/fhir/src/test/java/org/dhis2/fhir/adapter/fhir/metadata/repository/validator/BeforeCreateSaveTrackedEntityRuleValidatorTest.java b/fhir/src/test/java/org/dhis2/fhir/adapter/fhir/metadata/repository/validator/BeforeCreateSaveTrackedEntityRuleValidatorTest.java index 3995779f..38e26009 100644 --- a/fhir/src/test/java/org/dhis2/fhir/adapter/fhir/metadata/repository/validator/BeforeCreateSaveTrackedEntityRuleValidatorTest.java +++ b/fhir/src/test/java/org/dhis2/fhir/adapter/fhir/metadata/repository/validator/BeforeCreateSaveTrackedEntityRuleValidatorTest.java @@ -28,16 +28,312 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import org.apache.commons.lang3.StringUtils; import org.dhis2.fhir.adapter.fhir.AbstractJpaRepositoryTest; -import org.junit.Ignore; +import org.dhis2.fhir.adapter.fhir.metadata.model.CodeSet; +import org.dhis2.fhir.adapter.fhir.metadata.model.ExecutableScript; +import org.dhis2.fhir.adapter.fhir.metadata.model.FhirResourceType; +import org.dhis2.fhir.adapter.fhir.metadata.model.MappedTrackedEntity; +import org.dhis2.fhir.adapter.fhir.metadata.model.TrackedEntityRule; +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.Test; +import org.springframework.http.MediaType; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; /** * Validator tests for the corresponding repository. * * @author volsch */ -@Ignore +@SuppressWarnings( "JpaQlInspection" ) public class BeforeCreateSaveTrackedEntityRuleValidatorTest extends AbstractJpaRepositoryTest { + public static final String RESOURCE_PATH = "/api/trackedEntityRules"; + + public static final String AUTHORIZATION_HEADER_VALUE = CODE_MAPPING_AUTHORIZATION_HEADER_VALUE; + + private MappedTrackedEntity mappedTrackedEntity; + + private ExecutableScript teiLookupScript; + + private ExecutableScript locationLookupScript; + + private ExecutableScript orgLookupScript; + + private ExecutableScript applicableInScript; + + private ExecutableScript transformInScript; + + private ExecutableScript otherTransformInScript; + + private CodeSet applicableCodeSet; + + private TrackedEntityRule entity; + + @Before + public void before() + { + mappedTrackedEntity = entityManager.createQuery( "SELECT e FROM MappedTrackedEntity e WHERE e.name=:name", MappedTrackedEntity.class ) + .setParameter( "name", "Person" ).getSingleResult(); + teiLookupScript = entityManager.createQuery( "SELECT e FROM ExecutableScript e WHERE e.code=:code", ExecutableScript.class ) + .setParameter( "code", "PATIENT_TEI_LOOKUP" ).getSingleResult(); + locationLookupScript = entityManager.createQuery( "SELECT e FROM ExecutableScript e WHERE e.code=:code", ExecutableScript.class ) + .setParameter( "code", "EXTRACT_FHIR_PATIENT_GEO_LOCATION" ).getSingleResult(); + orgLookupScript = entityManager.createQuery( "SELECT e FROM ExecutableScript e WHERE e.code=:code", ExecutableScript.class ) + .setParameter( "code", "EXTRACT_FHIR_PATIENT_DHIS_ORG_UNIT_CODE" ).getSingleResult(); + applicableInScript = entityManager.createQuery( "SELECT e FROM ExecutableScript e WHERE e.code=:code", ExecutableScript.class ) + .setParameter( "code", "TRUE" ).getSingleResult(); + transformInScript = entityManager.createQuery( "SELECT e FROM ExecutableScript e WHERE e.code=:code", ExecutableScript.class ) + .setParameter( "code", "TRANSFORM_FHIR_PATIENT_DHIS_PERSON" ).getSingleResult(); + otherTransformInScript = entityManager.createQuery( "SELECT e FROM ExecutableScript e WHERE e.code=:code", ExecutableScript.class ) + .setParameter( "code", "CP_OPV_DOSE" ).getSingleResult(); + applicableCodeSet = entityManager.createQuery( "SELECT e FROM CodeSet e WHERE e.code=:code", CodeSet.class ) + .setParameter( "code", "ALL_DTP_DTAP" ).getSingleResult(); + + entity = new TrackedEntityRule(); + entity.setEnabled( false ); + entity.setEvaluationOrder( Integer.MIN_VALUE ); + entity.setName( createUnique() ); + entity.setFhirResourceType( FhirResourceType.PATIENT ); + entity.setDescription( createUnique() ); + } + + @Test + public void testNameBlank() throws Exception + { + entity.setName( " " ); + mockMvc.perform( post( RESOURCE_PATH ).header( AUTHORIZATION_HEADER_NAME, AUTHORIZATION_HEADER_VALUE ) + .contentType( MediaType.APPLICATION_JSON ).content( replaceJsonEntityReferences( entity, + JsonEntityValue.create( "trackedEntity", "trackedEntities", mappedTrackedEntity.getId().toString() ), + JsonEntityValue.create( "teiLookupScript", "executableScripts", teiLookupScript.getId().toString() ), + JsonEntityValue.create( "locationLookupScript", "executableScripts", locationLookupScript.getId().toString() ), + JsonEntityValue.create( "orgUnitLookupScript", "executableScripts", orgLookupScript.getId().toString() ), + JsonEntityValue.create( "applicableInScript", "executableScripts", applicableInScript.getId().toString() ), + JsonEntityValue.create( "transformInScript", "executableScripts", transformInScript.getId().toString() ), + JsonEntityValue.create( "applicableCodeSet", "codeSets", applicableCodeSet.getId().toString() ) ) ) ) + .andExpect( status().isBadRequest() ).andExpect( jsonPath( "errors[0].property", Matchers.is( "name" ) ) ); + } + + @Test + public void testNameLength() throws Exception + { + entity.setName( StringUtils.repeat( 'a', TrackedEntityRule.MAX_NAME_LENGTH + 1 ) ); + mockMvc.perform( post( RESOURCE_PATH ).header( AUTHORIZATION_HEADER_NAME, AUTHORIZATION_HEADER_VALUE ) + .contentType( MediaType.APPLICATION_JSON ).content( replaceJsonEntityReferences( entity, + JsonEntityValue.create( "trackedEntity", "trackedEntities", mappedTrackedEntity.getId().toString() ), + JsonEntityValue.create( "teiLookupScript", "executableScripts", teiLookupScript.getId().toString() ), + JsonEntityValue.create( "locationLookupScript", "executableScripts", locationLookupScript.getId().toString() ), + JsonEntityValue.create( "orgUnitLookupScript", "executableScripts", orgLookupScript.getId().toString() ), + JsonEntityValue.create( "applicableInScript", "executableScripts", applicableInScript.getId().toString() ), + JsonEntityValue.create( "transformInScript", "executableScripts", transformInScript.getId().toString() ), + JsonEntityValue.create( "applicableCodeSet", "codeSets", applicableCodeSet.getId().toString() ) ) ) ) + .andExpect( status().isBadRequest() ).andExpect( jsonPath( "errors[0].property", Matchers.is( "name" ) ) ); + } + + @Test + public void testFhirResourceTypeNull() throws Exception + { + entity.setFhirResourceType( null ); + mockMvc.perform( post( RESOURCE_PATH ).header( AUTHORIZATION_HEADER_NAME, AUTHORIZATION_HEADER_VALUE ) + .contentType( MediaType.APPLICATION_JSON ).content( replaceJsonEntityReferences( entity, + JsonEntityValue.create( "trackedEntity", "trackedEntities", mappedTrackedEntity.getId().toString() ), + JsonEntityValue.create( "teiLookupScript", "executableScripts", teiLookupScript.getId().toString() ), + JsonEntityValue.create( "locationLookupScript", "executableScripts", locationLookupScript.getId().toString() ), + JsonEntityValue.create( "orgUnitLookupScript", "executableScripts", orgLookupScript.getId().toString() ), + JsonEntityValue.create( "applicableInScript", "executableScripts", applicableInScript.getId().toString() ), + JsonEntityValue.create( "transformInScript", "executableScripts", transformInScript.getId().toString() ), + JsonEntityValue.create( "applicableCodeSet", "codeSets", applicableCodeSet.getId().toString() ) ) ) ) + .andExpect( status().isBadRequest() ).andExpect( jsonPath( "errors[0].property", Matchers.is( "fhirResourceType" ) ) ); + } + + @Test + public void testTrackedEntityNull() throws Exception + { + mockMvc.perform( post( RESOURCE_PATH ).header( AUTHORIZATION_HEADER_NAME, AUTHORIZATION_HEADER_VALUE ) + .contentType( MediaType.APPLICATION_JSON ).content( replaceJsonEntityReferences( entity, + JsonEntityValue.create( "teiLookupScript", "executableScripts", teiLookupScript.getId().toString() ), + JsonEntityValue.create( "locationLookupScript", "executableScripts", locationLookupScript.getId().toString() ), + JsonEntityValue.create( "orgUnitLookupScript", "executableScripts", orgLookupScript.getId().toString() ), + JsonEntityValue.create( "applicableInScript", "executableScripts", applicableInScript.getId().toString() ), + JsonEntityValue.create( "transformInScript", "executableScripts", transformInScript.getId().toString() ), + JsonEntityValue.create( "applicableCodeSet", "codeSets", applicableCodeSet.getId().toString() ) ) ) ) + .andExpect( status().isBadRequest() ).andExpect( jsonPath( "errors[0].property", Matchers.is( "trackedEntity" ) ) ); + } + + @Test + public void testTransformInScriptNull() throws Exception + { + mockMvc.perform( post( RESOURCE_PATH ).header( AUTHORIZATION_HEADER_NAME, AUTHORIZATION_HEADER_VALUE ) + .contentType( MediaType.APPLICATION_JSON ).content( replaceJsonEntityReferences( entity, + JsonEntityValue.create( "trackedEntity", "trackedEntities", mappedTrackedEntity.getId().toString() ), + JsonEntityValue.create( "teiLookupScript", "executableScripts", teiLookupScript.getId().toString() ), + JsonEntityValue.create( "locationLookupScript", "executableScripts", locationLookupScript.getId().toString() ), + JsonEntityValue.create( "orgUnitLookupScript", "executableScripts", orgLookupScript.getId().toString() ), + JsonEntityValue.create( "applicableInScript", "executableScripts", applicableInScript.getId().toString() ), + JsonEntityValue.create( "applicableCodeSet", "codeSets", applicableCodeSet.getId().toString() ) ) ) ) + .andExpect( status().isBadRequest() ).andExpect( jsonPath( "errors[0].property", Matchers.is( "transformInScript" ) ) ); + } + + @Test + public void testMinimal() throws Exception + { + mockMvc.perform( post( RESOURCE_PATH ).header( AUTHORIZATION_HEADER_NAME, AUTHORIZATION_HEADER_VALUE ) + .contentType( MediaType.APPLICATION_JSON ).content( replaceJsonEntityReferences( entity, + JsonEntityValue.create( "trackedEntity", "trackedEntities", mappedTrackedEntity.getId().toString() ), + JsonEntityValue.create( "transformInScript", "executableScripts", transformInScript.getId().toString() ) ) ) ) + .andExpect( status().isCreated() ); + } + + @Test + public void testTeiLookupTransformation() throws Exception + { + mockMvc.perform( post( RESOURCE_PATH ).header( AUTHORIZATION_HEADER_NAME, AUTHORIZATION_HEADER_VALUE ) + .contentType( MediaType.APPLICATION_JSON ).content( replaceJsonEntityReferences( entity, + JsonEntityValue.create( "trackedEntity", "trackedEntities", mappedTrackedEntity.getId().toString() ), + JsonEntityValue.create( "teiLookupScript", "executableScripts", transformInScript.getId().toString() ), + JsonEntityValue.create( "locationLookupScript", "executableScripts", locationLookupScript.getId().toString() ), + JsonEntityValue.create( "orgUnitLookupScript", "executableScripts", orgLookupScript.getId().toString() ), + JsonEntityValue.create( "applicableInScript", "executableScripts", applicableInScript.getId().toString() ), + JsonEntityValue.create( "transformInScript", "executableScripts", transformInScript.getId().toString() ), + JsonEntityValue.create( "applicableCodeSet", "codeSets", applicableCodeSet.getId().toString() ) ) ) ) + .andExpect( status().isBadRequest() ).andExpect( jsonPath( "errors[0].property", Matchers.is( "teiLookupScript" ) ) ); + } + + @Test + public void testTeiLookupBoolean() throws Exception + { + mockMvc.perform( post( RESOURCE_PATH ).header( AUTHORIZATION_HEADER_NAME, AUTHORIZATION_HEADER_VALUE ) + .contentType( MediaType.APPLICATION_JSON ).content( replaceJsonEntityReferences( entity, + JsonEntityValue.create( "trackedEntity", "trackedEntities", mappedTrackedEntity.getId().toString() ), + JsonEntityValue.create( "teiLookupScript", "executableScripts", applicableInScript.getId().toString() ), + JsonEntityValue.create( "locationLookupScript", "executableScripts", locationLookupScript.getId().toString() ), + JsonEntityValue.create( "orgUnitLookupScript", "executableScripts", orgLookupScript.getId().toString() ), + JsonEntityValue.create( "applicableInScript", "executableScripts", applicableInScript.getId().toString() ), + JsonEntityValue.create( "transformInScript", "executableScripts", transformInScript.getId().toString() ), + JsonEntityValue.create( "applicableCodeSet", "codeSets", applicableCodeSet.getId().toString() ) ) ) ) + .andExpect( status().isBadRequest() ).andExpect( jsonPath( "errors[0].property", Matchers.is( "teiLookupScript" ) ) ); + } + + @Test + public void testLocationLookupTransformation() throws Exception + { + mockMvc.perform( post( RESOURCE_PATH ).header( AUTHORIZATION_HEADER_NAME, AUTHORIZATION_HEADER_VALUE ) + .contentType( MediaType.APPLICATION_JSON ).content( replaceJsonEntityReferences( entity, + JsonEntityValue.create( "trackedEntity", "trackedEntities", mappedTrackedEntity.getId().toString() ), + JsonEntityValue.create( "teiLookupScript", "executableScripts", teiLookupScript.getId().toString() ), + JsonEntityValue.create( "locationLookupScript", "executableScripts", transformInScript.getId().toString() ), + JsonEntityValue.create( "orgUnitLookupScript", "executableScripts", orgLookupScript.getId().toString() ), + JsonEntityValue.create( "applicableInScript", "executableScripts", applicableInScript.getId().toString() ), + JsonEntityValue.create( "transformInScript", "executableScripts", transformInScript.getId().toString() ), + JsonEntityValue.create( "applicableCodeSet", "codeSets", applicableCodeSet.getId().toString() ) ) ) ) + .andExpect( status().isBadRequest() ).andExpect( jsonPath( "errors[0].property", Matchers.is( "locationLookupScript" ) ) ); + } + + @Test + public void testLocationLookupBoolean() throws Exception + { + mockMvc.perform( post( RESOURCE_PATH ).header( AUTHORIZATION_HEADER_NAME, AUTHORIZATION_HEADER_VALUE ) + .contentType( MediaType.APPLICATION_JSON ).content( replaceJsonEntityReferences( entity, + JsonEntityValue.create( "trackedEntity", "trackedEntities", mappedTrackedEntity.getId().toString() ), + JsonEntityValue.create( "teiLookupScript", "executableScripts", teiLookupScript.getId().toString() ), + JsonEntityValue.create( "locationLookupScript", "executableScripts", applicableInScript.getId().toString() ), + JsonEntityValue.create( "orgUnitLookupScript", "executableScripts", orgLookupScript.getId().toString() ), + JsonEntityValue.create( "applicableInScript", "executableScripts", applicableInScript.getId().toString() ), + JsonEntityValue.create( "transformInScript", "executableScripts", transformInScript.getId().toString() ), + JsonEntityValue.create( "applicableCodeSet", "codeSets", applicableCodeSet.getId().toString() ) ) ) ) + .andExpect( status().isBadRequest() ).andExpect( jsonPath( "errors[0].property", Matchers.is( "locationLookupScript" ) ) ); + } + + @Test + public void testOrgLookupScriptTransformation() throws Exception + { + mockMvc.perform( post( RESOURCE_PATH ).header( AUTHORIZATION_HEADER_NAME, AUTHORIZATION_HEADER_VALUE ) + .contentType( MediaType.APPLICATION_JSON ).content( replaceJsonEntityReferences( entity, + JsonEntityValue.create( "trackedEntity", "trackedEntities", mappedTrackedEntity.getId().toString() ), + JsonEntityValue.create( "teiLookupScript", "executableScripts", teiLookupScript.getId().toString() ), + JsonEntityValue.create( "locationLookupScript", "executableScripts", locationLookupScript.getId().toString() ), + JsonEntityValue.create( "orgUnitLookupScript", "executableScripts", transformInScript.getId().toString() ), + JsonEntityValue.create( "applicableInScript", "executableScripts", applicableInScript.getId().toString() ), + JsonEntityValue.create( "transformInScript", "executableScripts", transformInScript.getId().toString() ), + JsonEntityValue.create( "applicableCodeSet", "codeSets", applicableCodeSet.getId().toString() ) ) ) ) + .andExpect( status().isBadRequest() ).andExpect( jsonPath( "errors[0].property", Matchers.is( "orgUnitLookupScript" ) ) ); + } + + @Test + public void testOrgLookupScriptBoolean() throws Exception + { + mockMvc.perform( post( RESOURCE_PATH ).header( AUTHORIZATION_HEADER_NAME, AUTHORIZATION_HEADER_VALUE ) + .contentType( MediaType.APPLICATION_JSON ).content( replaceJsonEntityReferences( entity, + JsonEntityValue.create( "trackedEntity", "trackedEntities", mappedTrackedEntity.getId().toString() ), + JsonEntityValue.create( "teiLookupScript", "executableScripts", teiLookupScript.getId().toString() ), + JsonEntityValue.create( "locationLookupScript", "executableScripts", locationLookupScript.getId().toString() ), + JsonEntityValue.create( "orgUnitLookupScript", "executableScripts", applicableInScript.getId().toString() ), + JsonEntityValue.create( "applicableInScript", "executableScripts", applicableInScript.getId().toString() ), + JsonEntityValue.create( "transformInScript", "executableScripts", transformInScript.getId().toString() ), + JsonEntityValue.create( "applicableCodeSet", "codeSets", applicableCodeSet.getId().toString() ) ) ) ) + .andExpect( status().isBadRequest() ).andExpect( jsonPath( "errors[0].property", Matchers.is( "orgUnitLookupScript" ) ) ); + } + + @Test + public void testApplicableInScriptTransformation() throws Exception + { + mockMvc.perform( post( RESOURCE_PATH ).header( AUTHORIZATION_HEADER_NAME, AUTHORIZATION_HEADER_VALUE ) + .contentType( MediaType.APPLICATION_JSON ).content( replaceJsonEntityReferences( entity, + JsonEntityValue.create( "trackedEntity", "trackedEntities", mappedTrackedEntity.getId().toString() ), + JsonEntityValue.create( "teiLookupScript", "executableScripts", teiLookupScript.getId().toString() ), + JsonEntityValue.create( "locationLookupScript", "executableScripts", locationLookupScript.getId().toString() ), + JsonEntityValue.create( "orgUnitLookupScript", "executableScripts", orgLookupScript.getId().toString() ), + JsonEntityValue.create( "applicableInScript", "executableScripts", transformInScript.getId().toString() ), + JsonEntityValue.create( "transformInScript", "executableScripts", transformInScript.getId().toString() ), + JsonEntityValue.create( "applicableCodeSet", "codeSets", applicableCodeSet.getId().toString() ) ) ) ) + .andExpect( status().isBadRequest() ).andExpect( jsonPath( "errors[0].property", Matchers.is( "applicableInScript" ) ) ); + } + + @Test + public void testApplicableInScriptLocation() throws Exception + { + mockMvc.perform( post( RESOURCE_PATH ).header( AUTHORIZATION_HEADER_NAME, AUTHORIZATION_HEADER_VALUE ) + .contentType( MediaType.APPLICATION_JSON ).content( replaceJsonEntityReferences( entity, + JsonEntityValue.create( "trackedEntity", "trackedEntities", mappedTrackedEntity.getId().toString() ), + JsonEntityValue.create( "teiLookupScript", "executableScripts", teiLookupScript.getId().toString() ), + JsonEntityValue.create( "locationLookupScript", "executableScripts", locationLookupScript.getId().toString() ), + JsonEntityValue.create( "orgUnitLookupScript", "executableScripts", orgLookupScript.getId().toString() ), + JsonEntityValue.create( "applicableInScript", "executableScripts", locationLookupScript.getId().toString() ), + JsonEntityValue.create( "transformInScript", "executableScripts", transformInScript.getId().toString() ), + JsonEntityValue.create( "applicableCodeSet", "codeSets", applicableCodeSet.getId().toString() ) ) ) ) + .andExpect( status().isBadRequest() ).andExpect( jsonPath( "errors[0].property", Matchers.is( "applicableInScript" ) ) ); + } + + @Test + public void testTransformInScriptEvaluate() throws Exception + { + mockMvc.perform( post( RESOURCE_PATH ).header( AUTHORIZATION_HEADER_NAME, AUTHORIZATION_HEADER_VALUE ) + .contentType( MediaType.APPLICATION_JSON ).content( replaceJsonEntityReferences( entity, + JsonEntityValue.create( "trackedEntity", "trackedEntities", mappedTrackedEntity.getId().toString() ), + JsonEntityValue.create( "teiLookupScript", "executableScripts", teiLookupScript.getId().toString() ), + JsonEntityValue.create( "locationLookupScript", "executableScripts", locationLookupScript.getId().toString() ), + JsonEntityValue.create( "orgUnitLookupScript", "executableScripts", orgLookupScript.getId().toString() ), + JsonEntityValue.create( "applicableInScript", "executableScripts", applicableInScript.getId().toString() ), + JsonEntityValue.create( "transformInScript", "executableScripts", teiLookupScript.getId().toString() ), + JsonEntityValue.create( "applicableCodeSet", "codeSets", applicableCodeSet.getId().toString() ) ) ) ) + .andExpect( status().isBadRequest() ).andExpect( jsonPath( "errors[0].property", Matchers.is( "transformInScript" ) ) ); + } + @Test + public void testTransformInScriptResourceType() throws Exception + { + mockMvc.perform( post( RESOURCE_PATH ).header( AUTHORIZATION_HEADER_NAME, AUTHORIZATION_HEADER_VALUE ) + .contentType( MediaType.APPLICATION_JSON ).content( replaceJsonEntityReferences( entity, + JsonEntityValue.create( "trackedEntity", "trackedEntities", mappedTrackedEntity.getId().toString() ), + JsonEntityValue.create( "teiLookupScript", "executableScripts", teiLookupScript.getId().toString() ), + JsonEntityValue.create( "locationLookupScript", "executableScripts", locationLookupScript.getId().toString() ), + JsonEntityValue.create( "orgUnitLookupScript", "executableScripts", orgLookupScript.getId().toString() ), + JsonEntityValue.create( "applicableInScript", "executableScripts", applicableInScript.getId().toString() ), + JsonEntityValue.create( "transformInScript", "executableScripts", otherTransformInScript.getId().toString() ), + JsonEntityValue.create( "applicableCodeSet", "codeSets", applicableCodeSet.getId().toString() ) ) ) ) + .andExpect( status().isBadRequest() ).andExpect( jsonPath( "errors[0].property", Matchers.is( "transformInScript" ) ) ); + } } \ No newline at end of file diff --git a/fhir/src/test/resources/data.sql b/fhir/src/test/resources/data.sql index 55ea7e2d..768469d4 100644 --- a/fhir/src/test/resources/data.sql +++ b/fhir/src/test/resources/data.sql @@ -68,6 +68,16 @@ VALUES ('1a2950cf08424dd39453284fb08789d3', 0, CURRENT_TIMESTAMP(), CURRENT_TIME INSERT INTO fhir_executable_script_argument(id, executable_script_id, script_argument_id, override_value, enabled) VALUES ('4a8ba21510e946f2921fda3973836119', '1a2950cf08424dd39453284fb08789d3', '44134ba8d77f4c4d90c6b434ffbe7958', 'CODE:DE_2006104', TRUE); +-- Script that returns boolean value true every time +INSERT INTO fhir_script (id, version, name, code, description, script_type, return_type, input_type, output_type) +VALUES ('5b37861d94424e13ac9f88a893e91ce9', 0, 'True', 'TRUE', 'Returns Boolean True.', 'EVALUATE', 'BOOLEAN', NULL, NULL); +INSERT INTO fhir_script_source (id, version, script_id, source_text, source_type) +VALUES ('edcb402e94b4495388463a4d1c0dad6e', 0, '5b37861d94424e13ac9f88a893e91ce9', 'true', 'JAVASCRIPT'); +INSERT INTO fhir_script_source_version (script_source_id, fhir_version) +VALUES ('edcb402e94b4495388463a4d1c0dad6e', 'DSTU3'); +INSERT INTO fhir_executable_script (id, version, script_id, name, code, description) +VALUES ('9299b82eb90a45428b78200cadff3d7d', 0, '5b37861d94424e13ac9f88a893e91ce9', 'True', 'TRUE', 'Returns Boolean True.'); + INSERT INTO fhir_script (id, version, created_at, last_updated_at, last_updated_by, code, name, description, script_type, return_type, input_type, output_type) VALUES ('f1da6937e2fe47a4b0f38bbff7818ee1', 0, CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP(), '2h2maqu827d', 'TRANSFORM_FHIR_OB_BODY_WEIGHT', 'Transforms FHIR Observation Body Weight', 'Transforms FHIR Observation Body Weight to a data element and performs weight unit conversion.', 'TRANSFORM_TO_DHIS', 'BOOLEAN', 'FHIR_OBSERVATION', 'DHIS_EVENT'); @@ -123,6 +133,36 @@ INSERT INTO fhir_code_set(id, version, created_at, last_updated_at, last_updated VALUES ('bb66ee918e86422cbb005a90ac95a558', 0, CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP(), '2h2maqu827d', '7090561ef45b411e99c065fa1d145018', 'All DTP/DTaP', 'ALL_DTP_DTAP', 'All DTP/DTaP vaccines.'); INSERT INTO fhir_code_set_value(id, code_set_id, code_id, enabled) SELECT RANDOM_UUID(), 'bb66ee918e86422cbb005a90ac95a558', id, TRUE FROM fhir_code WHERE code IN ('VACCINE_106', 'VACCINE_20'); + +-- Script that performs the lookup of TEI FHIR Resource from FHIR Observation +INSERT INTO fhir_script (id, version, name, code, description, script_type, return_type, input_type, output_type) +VALUES ('8b5ab5f1363d4ccb8e63d6ecf25b3017', 0, 'Observation TEI Lookup', 'OBSERVATION_TEI_LOOKUP', 'Lookup of the Tracked Entity Instance FHIR Resource from FHIR Observation.', 'EVALUATE', 'FHIR_RESOURCE', 'FHIR_OBSERVATION', NULL); +INSERT INTO fhir_script_variable (script_id, variable) +VALUES ('8b5ab5f1363d4ccb8e63d6ecf25b3017', 'CONTEXT'); +INSERT INTO fhir_script_variable (script_id, variable) +VALUES ('8b5ab5f1363d4ccb8e63d6ecf25b3017', 'INPUT'); +INSERT INTO fhir_script_source (id, version, script_id, source_text, source_type) +VALUES ('960d2e6c247948a2b04eb14879e71d14', 0, '8b5ab5f1363d4ccb8e63d6ecf25b3017', 'referenceUtils.getResource(input.subject, ''PATIENT'')', 'JAVASCRIPT'); +INSERT INTO fhir_script_source_version (script_source_id, fhir_version) +VALUES ('960d2e6c247948a2b04eb14879e71d14', 'DSTU3'); +INSERT INTO fhir_executable_script (id, version, script_id, name, code, description) +VALUES ('1b6a2f75cb4a47b18e903dfb4db07d36', 0, '8b5ab5f1363d4ccb8e63d6ecf25b3017', + 'Observation TEI Lookup', 'OBSERVATION_TEI_LOOKUP', 'Lookup of the Tracked Entity Instance FHIR Resource from FHIR Observation.'); + +-- Script that performs the lookup of TEI FHIR Resource from FHIR Patient (the patient itself) +INSERT INTO fhir_script (id, version, name, code, description, script_type, return_type, input_type, output_type) +VALUES ('8b5ab5f1363d4ccb8e63d6ecf25b3018', 0, 'Patient TEI Lookup', 'PATIENT_TEI_LOOKUP', 'Lookup of the Tracked Entity Instance FHIR Resource from FHIR Patient.', 'EVALUATE', 'FHIR_RESOURCE', 'FHIR_PATIENT', NULL); +INSERT INTO fhir_script_variable (script_id, variable) +VALUES ('8b5ab5f1363d4ccb8e63d6ecf25b3018', 'CONTEXT'); +INSERT INTO fhir_script_variable (script_id, variable) +VALUES ('8b5ab5f1363d4ccb8e63d6ecf25b3018', 'INPUT'); +INSERT INTO fhir_script_source (id, version, script_id, source_text, source_type) +VALUES ('960d2e6c247948a2b04eb14879e71d15', 0, '8b5ab5f1363d4ccb8e63d6ecf25b3018', 'input', 'JAVASCRIPT'); +INSERT INTO fhir_script_source_version (script_source_id, fhir_version) +VALUES ('960d2e6c247948a2b04eb14879e71d15', 'DSTU3'); +INSERT INTO fhir_executable_script (id, version, script_id, name, code, description) +VALUES ('1b6a2f75cb4a47b18e903dfb4db07d37', 0, '8b5ab5f1363d4ccb8e63d6ecf25b3018', + 'Patient TEI Lookup', 'PATIENT_TEI_LOOKUP', 'Lookup of the Tracked Entity Instance FHIR Resource from FHIR Patient.'); INSERT INTO fhir_script (id, version, created_at, last_updated_at, last_updated_by, name, code, description, script_type, return_type, input_type, output_type) VALUES ('a250e109a13542b28bdb1c050c1d384c', 0, CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP(), '2h2maqu827d', 'Org Unit Code from Patient Org', 'EXTRACT_FHIR_PATIENT_DHIS_ORG_UNIT_CODE', diff --git a/pom.xml b/pom.xml index 1368b3e0..279b87df 100644 --- a/pom.xml +++ b/pom.xml @@ -151,6 +151,15 @@ -parameters + + org.apache.maven.plugins + maven-jar-plugin + + + false + + + org.apache.maven.plugins maven-surefire-plugin