Skip to content

Commit

Permalink
added ehr access to the valdiation flow tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ppazos committed Oct 16, 2022
1 parent 4012e04 commit 2a479ff
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 39 deletions.
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
/**
*
*/
package com.cabolabs.openehr.dto_1_0_2.ehr

import com.cabolabs.openehr.rm_1_0_2.ehr.EhrStatus
import com.cabolabs.openehr.rm_1_0_2.ehr.EhrAccess
import com.cabolabs.openehr.rm_1_0_2.common.directory.Folder
import com.cabolabs.openehr.rm_1_0_2.composition.Composition
import com.cabolabs.openehr.rm_1_0_2.support.identification.HierObjectId
import com.cabolabs.openehr.rm_1_0_2.data_types.quantity.date_time.DvDateTime
import com.cabolabs.openehr.dto_1_0_2.common.change_control.ContributionDto


/**
* @author pablo.pazos@cabolabs.com
*
Expand All @@ -21,7 +18,7 @@ class EhrDto {
HierObjectId ehr_id
DvDateTime time_created
EhrStatus ehr_status
// TODO: ehr_access
EhrAccess ehr_access
List<Composition> compositions
Folder directory
List<ContributionDto> contributions
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.cabolabs.openehr.formats

import com.cabolabs.openehr.rm_1_0_2.ehr.Ehr
import com.cabolabs.openehr.rm_1_0_2.ehr.EhrStatus
import com.cabolabs.openehr.rm_1_0_2.ehr.*
import com.cabolabs.openehr.rm_1_0_2.common.generic.*
import com.cabolabs.openehr.rm_1_0_2.common.archetyped.Archetyped
import com.cabolabs.openehr.rm_1_0_2.common.archetyped.Locatable
Expand Down Expand Up @@ -37,9 +36,10 @@ import org.apache.log4j.Logger

import groovy.json.JsonSlurper

@groovy.util.logging.Log4j
class OpenEhrJsonParser {

private Logger log = Logger.getLogger(getClass())
//private Logger log = Logger.getLogger(getClass())

def jsonValidator

Expand Down Expand Up @@ -153,37 +153,13 @@ class OpenEhrJsonParser {

ehr.ehr_status = this.parseEHR_STATUS(map.ehr_status)

return ehr
}

// This is to parse the API POST /ehr payload
// FIXME: shouldn't this be done in parseLocatable?
/*
EhrStatus parseEhrStatus(String json)
{
def slurper = new JsonSlurper()
def map = slurper.parseText(json)
if (this.schemaValidate)
if (map.ehr_access)
{
if (!map.archetype_details || !map.archetype_details.rm_version) // rm version aware
{
throw new Exception("archetype_details.rm_version is required for the root of any archetypable class")
}
this.jsonValidator = new JsonInstanceValidation(this.schemaFlavor, map.archetype_details.rm_version)
def errors = jsonValidator.validate(json)
if (errors)
{
this.jsonValidationErrors = errors
return
}
ehr.ehr_access = this.parseEHR_ACCESS(map.ehr_access)
}

return parseEHR_STATUS(map)
return ehr
}
*/

// used to parse compositions and other descendant from Locatable
// TODO: FOLDER and EHR_STATUS are above, we might need to use this one instead
Expand Down Expand Up @@ -689,6 +665,26 @@ class OpenEhrJsonParser {
return status
}

/**
* This method is here for completeness, most implementations don't even have support for EHR_ACCESS internally.
*/
private EhrAccess parseEHR_ACCESS(Map map)
{
def access = new EhrAccess()

this.fillLOCATABLE(access, map, null, '/', '/')

if (map.settings)
{
log.warn("EHR_ACCESS.settings has a value but was not parsed")
// Since ACCESS_CONTROL_SETTINGS is abstract and doesn't have any concrete
// subclasses, we can't parse it.
//access.settings = this.parseACCESS_CONTROL_SETTINGS(map.access)
}

return access
}

private Composition parseCOMPOSITION(Map json)
{
Composition compo = new Composition()
Expand Down
24 changes: 24 additions & 0 deletions src/main/groovy/com/cabolabs/openehr/rm_1_0_2/ehr/EhrAccess.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.cabolabs.openehr.rm_1_0_2.ehr

import com.cabolabs.openehr.rm_1_0_2.common.archetyped.Pathable
import com.cabolabs.openehr.rm_1_0_2.common.archetyped.Locatable
import com.cabolabs.openehr.rm_1_0_2.security.AccessControlSettings

/**
* @author pablo.pazos@cabolabs.com
*
*/
class EhrAccess extends Locatable {

AccessControlSettings settings

@Override
void fillPathable(Pathable parent, String parentAttribute)
{
this.path = ((parent.path != '/') ? '/' : '') + parentAttribute.replaceAll(/\[\d+\]/, '')
this.dataPath = ((parent.dataPath != '/') ? '/' : '') + parentAttribute
this.parent = parent

//this.other_details.fillPathable(this, "other_details")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.cabolabs.openehr.rm_1_0_2.security

/**
* @author pablo.pazos@cabolabs.com
*
*/
abstract class AccessControlSettings {

}
34 changes: 34 additions & 0 deletions src/main/groovy/com/cabolabs/openehr/validation/RmValidator.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.cabolabs.openehr.rm_1_0_2.common.archetyped.Pathable
import com.cabolabs.openehr.rm_1_0_2.common.archetyped.Locatable
import com.cabolabs.openehr.rm_1_0_2.common.directory.Folder
import com.cabolabs.openehr.rm_1_0_2.demographic.*
import com.cabolabs.openehr.dto_1_0_2.ehr.EhrDto

class RmValidator {

Expand Down Expand Up @@ -76,6 +77,39 @@ class RmValidator {
return report
}

/**
* EhrDto is validated against the relaxed RM constraints. Since it's not Locatable it can't be validated
* against an OPT (unless we use the OPT as a RM representation). Based on the current REST API specification,
* the EhrDto will be returned in the response, so it will have system_id, ehr_id, time_created and ehr_status
* (could be the defaullt one). For the API we don't require the ehr_access to be there.
*/
RmValidationReport dovalidate(EhrDto ehr)
{
RmValidationReport report = new RmValidationReport()

if (!ehr.system_id)
{
report.addError("/system_id", "attribute is not present but is required")
}

if (!ehr.ehr_id)
{
report.addError("/ehr_id", "attribute is not present but is required")
}

if (!ehr.ehr_status)
{
report.addError("/ehr_status", "attribute is not present but is required")
}

if (!ehr.time_created)
{
report.addError("/time_created", "attribute is not present but is required")
}

return report
}

// the namespace is where the OPT is stored/cached, allows to implement multi-tenancy
RmValidationReport dovalidate(Locatable rm_object, String namespace)
{
Expand Down
25 changes: 21 additions & 4 deletions src/test/groovy/com/cabolabs/openehr/opt/ValidationFlowTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ class ValidationFlowTest extends GroovyTestCase {
"name": {
"_type": "DV_TEXT",
"value": "EHR Status"
},
"settings": {
"value": "dummy"
}
},
"time_created": {
Expand All @@ -140,8 +143,7 @@ class ValidationFlowTest extends GroovyTestCase {
def parser = new OpenEhrJsonParser(true) // does RM schema validation
EhrDto ehr = parser.parseEhrDto(json_ehr)

println parser.getJsonValidationErrors()

// parsed OK (validation doesn't retrieve any errors)
assert ehr

assert ehr.time_created.value == "2015-01-20T19:30:22.765+01:00"
Expand Down Expand Up @@ -277,15 +279,30 @@ class ValidationFlowTest extends GroovyTestCase {
RmValidator validator = new RmValidator()
RmValidationReport report = validator.dovalidate(ehr)

// TODO:
println report.errors
assert report.errors.find{ it.path == '/ehr_id' }.error == 'attribute is not present but is required'
assert report.errors.find{ it.path == '/ehr_status' }.error == 'attribute is not present but is required'
assert report.errors.find{ it.path == '/ehr_access' }.error == 'attribute is not present but is required'
assert report.errors.find{ it.path == '/time_created' }.error == 'attribute is not present but is required'

assert report.errors.size() == 4
}

void test_ehr_api_rm_invalid()
{
def ehr = new EhrDto(
system_id: new HierObjectId(
value: '8b201872-9d95-4ffa-adfe-4eaa4cfaecf0'
)
)

RmValidator validator = new RmValidator()
RmValidationReport report = validator.dovalidate(ehr)

assert report.errors.find{ it.path == '/ehr_id' }.error == 'attribute is not present but is required'
assert report.errors.find{ it.path == '/ehr_status' }.error == 'attribute is not present but is required'
assert report.errors.find{ it.path == '/time_created' }.error == 'attribute is not present but is required'

assert report.errors.size() == 3
}

// ===================================================
Expand Down

0 comments on commit 2a479ff

Please sign in to comment.