All recreating code systems with previously used URL

This commit is contained in:
James Agnew 2017-09-09 21:49:26 -07:00
parent 2bb01451ea
commit 805fbad6ce
12 changed files with 625 additions and 488 deletions

View File

@ -35,7 +35,7 @@ public class ValidationDataUploader extends BaseCommand {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ValidationDataUploader.class);
private ArrayList<IIdType> myExcludes;
private ArrayList<IIdType> myExcludes = new ArrayList<>();
private void filterBundle(ca.uhn.fhir.model.dstu2.resource.Bundle theBundle) {
for (Iterator<Entry> iter = theBundle.getEntry().iterator(); iter.hasNext(); ) {
@ -120,16 +120,8 @@ public class ValidationDataUploader extends BaseCommand {
}
FhirContext ctx = getSpecVersionContext(theCommandLine);
if (ctx.getVersion().getVersion() == FhirVersionEnum.DSTU2) {
uploadDefinitionsDstu2(targetServer, ctx);
} else if (ctx.getVersion().getVersion() == FhirVersionEnum.DSTU3) {
uploadDefinitionsDstu3(targetServer, ctx);
} else if (ctx.getVersion().getVersion() == FhirVersionEnum.R4) {
uploadDefinitionsR4(targetServer, ctx);
}
String exclude = theCommandLine.getOptionValue("e");
myExcludes = new ArrayList<>();
if (isNotBlank(exclude)) {
for (String next : exclude.split(",")) {
if (isNotBlank(next)) {
@ -140,6 +132,14 @@ public class ValidationDataUploader extends BaseCommand {
}
}
if (ctx.getVersion().getVersion() == FhirVersionEnum.DSTU2) {
uploadDefinitionsDstu2(targetServer, ctx);
} else if (ctx.getVersion().getVersion() == FhirVersionEnum.DSTU3) {
uploadDefinitionsDstu3(targetServer, ctx);
} else if (ctx.getVersion().getVersion() == FhirVersionEnum.R4) {
uploadDefinitionsR4(targetServer, ctx);
}
}
private void uploadDefinitionsDstu2(String targetServer, FhirContext ctx) throws CommandFailureException {

View File

@ -20,28 +20,39 @@ package ca.uhn.fhir.jpa.dao.dstu3;
* #L%
*/
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.util.*;
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport.CodeValidationResult;
import org.hl7.fhir.dstu3.hapi.validation.ValidationSupportChain;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.instance.model.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemDao;
import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemVersionDao;
import ca.uhn.fhir.jpa.entity.*;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
import ca.uhn.fhir.jpa.util.LogicUtil;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport.CodeValidationResult;
import org.hl7.fhir.dstu3.hapi.validation.ValidationSupportChain;
import org.hl7.fhir.dstu3.model.CodeSystem;
import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.dstu3.model.CodeableConcept;
import org.hl7.fhir.dstu3.model.Coding;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3<CodeSystem> implements IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> {
@ -50,6 +61,9 @@ public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3<CodeSys
@Autowired
private ITermCodeSystemVersionDao myCsvDao;
@Autowired
private ITermCodeSystemDao myCsDao;
@Autowired
private IHapiTerminologySvc myTerminologySvc;
@ -115,7 +129,7 @@ public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3<CodeSys
}
ourLog.info("Looking up {} / {}", system, code);
if (myValidationSupport.isCodeSystemSupported(getContext(), system)) {
ourLog.info("Code system {} is supported", system);
@ -133,7 +147,7 @@ public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3<CodeSys
return retVal;
}
}
// HapiWorkerContext ctx = new HapiWorkerContext(getContext(), myValidationSupport);
// ValueSetExpander expander = ctx.getExpander();
// ValueSet source = new ValueSet();
@ -165,8 +179,21 @@ public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3<CodeSys
}
@Override
protected void preDelete(CodeSystem theResourceToDelete, ResourceTable theEntityToDelete) {
super.preDelete(theResourceToDelete, theEntityToDelete);
String codeSystemUrl = theResourceToDelete.getUrl();
if (isNotBlank(codeSystemUrl)) {
TermCodeSystem persCs = myCsDao.findByCodeSystemUri(codeSystemUrl);
if (persCs != null) {
myTerminologySvc.deleteCodeSystem(persCs);
}
}
}
private List<TermConcept> toPersistedConcepts(List<ConceptDefinitionComponent> theConcept, TermCodeSystemVersion theCodeSystemVersion) {
ArrayList<TermConcept> retVal = new ArrayList<TermConcept>();
ArrayList<TermConcept> retVal = new ArrayList<>();
for (ConceptDefinitionComponent next : theConcept) {
if (isNotBlank(next.getCode())) {
@ -181,32 +208,35 @@ public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3<CodeSys
return retVal;
}
@Override
protected ResourceTable updateEntity(IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
ResourceTable retVal = super.updateEntity(theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
CodeSystem cs = (CodeSystem) theResource;
if (cs != null && isNotBlank(cs.getUrl())) {
String codeSystemUrl = cs.getUrl();
if (cs.getContent() == CodeSystemContentMode.COMPLETE || cs.getContent() == null) {
Long codeSystemResourcePid = retVal.getId();
if (retVal.getDeleted() != null) {
// deleting
} else if (cs.getContent() == CodeSystemContentMode.COMPLETE || cs.getContent() == null) {
ourLog.info("CodeSystem {} has a status of {}, going to store concepts in terminology tables", retVal.getIdDt().getValue(), cs.getContentElement().getValueAsString());
Long codeSystemResourcePid = retVal.getId();
TermCodeSystemVersion persCs = myCsvDao.findByCodeSystemResourceAndVersion(codeSystemResourcePid, retVal.getVersion());
if (persCs != null) {
ourLog.info("Code system version already exists in database");
} else {
persCs = new TermCodeSystemVersion();
persCs.setResource(retVal);
persCs.setResourceVersionId(retVal.getVersion());
persCs.getConcepts().addAll(toPersistedConcepts(cs.getConcept(), persCs));
ourLog.info("Code system has {} concepts", persCs.getConcepts().size());
myTerminologySvc.storeNewCodeSystemVersion(codeSystemResourcePid, codeSystemUrl, persCs);
}
}

View File

@ -20,28 +20,39 @@ package ca.uhn.fhir.jpa.dao.r4;
* #L%
*/
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.util.*;
import org.hl7.fhir.r4.hapi.ctx.ValidationSupportChain;
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport.CodeValidationResult;
import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode;
import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.instance.model.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemDao;
import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemVersionDao;
import ca.uhn.fhir.jpa.entity.*;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
import ca.uhn.fhir.jpa.util.LogicUtil;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport.CodeValidationResult;
import org.hl7.fhir.r4.hapi.ctx.ValidationSupportChain;
import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode;
import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.IdType;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class FhirResourceDaoCodeSystemR4 extends FhirResourceDaoR4<CodeSystem> implements IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> {
@ -49,10 +60,10 @@ public class FhirResourceDaoCodeSystemR4 extends FhirResourceDaoR4<CodeSystem> i
@Autowired
private ITermCodeSystemVersionDao myCsvDao;
@Autowired
private ITermCodeSystemDao myCsDao;
@Autowired
private IHapiTerminologySvc myTerminologySvc;
@Autowired
private ValidationSupportChain myValidationSupport;
@ -115,7 +126,7 @@ public class FhirResourceDaoCodeSystemR4 extends FhirResourceDaoR4<CodeSystem> i
}
ourLog.info("Looking up {} / {}", system, code);
if (myValidationSupport.isCodeSystemSupported(getContext(), system)) {
ourLog.info("Code system {} is supported", system);
@ -133,7 +144,7 @@ public class FhirResourceDaoCodeSystemR4 extends FhirResourceDaoR4<CodeSystem> i
return retVal;
}
}
// HapiWorkerContext ctx = new HapiWorkerContext(getContext(), myValidationSupport);
// ValueSetExpander expander = ctx.getExpander();
// ValueSet source = new ValueSet();
@ -165,6 +176,19 @@ public class FhirResourceDaoCodeSystemR4 extends FhirResourceDaoR4<CodeSystem> i
}
@Override
protected void preDelete(CodeSystem theResourceToDelete, ResourceTable theEntityToDelete) {
super.preDelete(theResourceToDelete, theEntityToDelete);
String codeSystemUrl = theResourceToDelete.getUrl();
if (isNotBlank(codeSystemUrl)) {
TermCodeSystem persCs = myCsDao.findByCodeSystemUri(codeSystemUrl);
if (persCs != null) {
myTerminologySvc.deleteCodeSystem(persCs);
}
}
}
private List<TermConcept> toPersistedConcepts(List<ConceptDefinitionComponent> theConcept, TermCodeSystemVersion theCodeSystemVersion) {
ArrayList<TermConcept> retVal = new ArrayList<TermConcept>();
@ -181,10 +205,10 @@ public class FhirResourceDaoCodeSystemR4 extends FhirResourceDaoR4<CodeSystem> i
return retVal;
}
@Override
protected ResourceTable updateEntity(IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
ResourceTable retVal = super.updateEntity(theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
CodeSystem cs = (CodeSystem) theResource;
@ -193,20 +217,20 @@ public class FhirResourceDaoCodeSystemR4 extends FhirResourceDaoR4<CodeSystem> i
String codeSystemUrl = cs.getUrl();
if (cs.getContent() == CodeSystemContentMode.COMPLETE || cs.getContent() == null) {
ourLog.info("CodeSystem {} has a status of {}, going to store concepts in terminology tables", retVal.getIdDt().getValue(), cs.getContentElement().getValueAsString());
Long codeSystemResourcePid = retVal.getId();
TermCodeSystemVersion persCs = myCsvDao.findByCodeSystemResourceAndVersion(codeSystemResourcePid, retVal.getVersion());
if (persCs != null) {
ourLog.info("Code system version already exists in database");
} else {
persCs = new TermCodeSystemVersion();
persCs.setResource(retVal);
persCs.setResourceVersionId(retVal.getVersion());
persCs.getConcepts().addAll(toPersistedConcepts(cs.getConcept(), persCs));
ourLog.info("Code system has {} concepts", persCs.getConcepts().size());
myTerminologySvc.storeNewCodeSystemVersion(codeSystemResourcePid, codeSystemUrl, persCs);
}
}

View File

@ -20,69 +20,59 @@ package ca.uhn.fhir.jpa.entity;
* #L%
*/
import javax.persistence.*;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.ForeignKey;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
//@formatter:off
@Table(name="TRM_CODESYSTEM", uniqueConstraints= {
@UniqueConstraint(name="IDX_CS_CODESYSTEM", columnNames= {"CODE_SYSTEM_URI"})
@Table(name = "TRM_CODESYSTEM", uniqueConstraints = {
@UniqueConstraint(name = "IDX_CS_CODESYSTEM", columnNames = {"CODE_SYSTEM_URI"})
})
@Entity()
//@formatter:on
public class TermCodeSystem implements Serializable {
private static final long serialVersionUID = 1L;
@Column(name="CODE_SYSTEM_URI", nullable=false)
@Column(name = "CODE_SYSTEM_URI", nullable = false)
private String myCodeSystemUri;
@OneToOne()
@JoinColumn(name="CURRENT_VERSION_PID", referencedColumnName="PID", nullable=true, foreignKey=@ForeignKey(name="FK_TRMCODESYSTEM_CURVER"))
@JoinColumn(name = "CURRENT_VERSION_PID", referencedColumnName = "PID", nullable = true, foreignKey = @ForeignKey(name = "FK_TRMCODESYSTEM_CURVER"))
private TermCodeSystemVersion myCurrentVersion;
@Id()
@SequenceGenerator(name = "SEQ_CODESYSTEM_PID", sequenceName = "SEQ_CODESYSTEM_PID")
@GeneratedValue(strategy=GenerationType.AUTO, generator="SEQ_CODESYSTEM_PID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CODESYSTEM_PID")
@Column(name = "PID")
private Long myPid;
@OneToOne()
@JoinColumn(name = "RES_ID", referencedColumnName = "RES_ID", nullable = false, updatable = false, foreignKey=@ForeignKey(name="FK_TRMCODESYSTEM_RES"))
@JoinColumn(name = "RES_ID", referencedColumnName = "RES_ID", nullable = false, updatable = false, foreignKey = @ForeignKey(name = "FK_TRMCODESYSTEM_RES"))
private ResourceTable myResource;
@Column(name = "RES_ID", insertable=false, updatable=false)
@Column(name = "RES_ID", insertable = false, updatable = false)
private Long myResourcePid;
public String getCodeSystemUri() {
return myCodeSystemUri;
}
public TermCodeSystemVersion getCurrentVersion() {
return myCurrentVersion;
}
public ResourceTable getResource() {
return myResource;
}
public void setCodeSystemUri(String theCodeSystemUri) {
myCodeSystemUri = theCodeSystemUri;
}
public TermCodeSystemVersion getCurrentVersion() {
return myCurrentVersion;
}
public void setCurrentVersion(TermCodeSystemVersion theCurrentVersion) {
myCurrentVersion = theCurrentVersion;
}
public Long getPid() {
return myPid;
}
public ResourceTable getResource() {
return myResource;
}
public void setResource(ResourceTable theResource) {
myResource = theResource;
}

View File

@ -618,4 +618,15 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
ourForceSaveDeferredAlwaysForUnitTest = theForceSaveDeferredAlwaysForUnitTest;
}
@Override
public void deleteCodeSystem(TermCodeSystem theCodeSystem) {
ourLog.info(" * Deleting code system {}", theCodeSystem.getPid());
for (TermCodeSystemVersion next : myCodeSystemVersionDao.findByCodeSystemResource(theCodeSystem.getPid())) {
myConceptParentChildLinkDao.deleteByCodeSystemVersion(next.getPid());
myConceptDao.deleteByCodeSystemVersion(next.getPid());
}
myCodeSystemDao.delete(theCodeSystem.getPid());
}
}

View File

@ -20,13 +20,12 @@ package ca.uhn.fhir.jpa.term;
* #L%
*/
import java.util.List;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.hl7.fhir.instance.hapi.validation.IValidationSupport;
import org.springframework.beans.factory.annotation.Autowired;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import java.util.List;
public class HapiTerminologySvcDstu2 extends BaseHapiTerminologySvc {
@ -46,5 +45,4 @@ public class HapiTerminologySvcDstu2 extends BaseHapiTerminologySvc {
}
}

View File

@ -24,12 +24,15 @@ import java.util.List;
import java.util.Set;
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.rest.api.server.RequestDetails;
public interface IHapiTerminologySvc {
void deleteCodeSystem(TermCodeSystem thePersCs);
Set<TermConcept> findCodesAbove(Long theCodeSystemResourcePid, Long theCodeSystemResourceVersionPid, String theCode);
Set<TermConcept> findCodesBelow(Long theCodeSystemResourcePid, Long theCodeSystemResourceVersionPid, String theCode);

View File

@ -28,6 +28,21 @@ import ca.uhn.fhir.util.TestUtil;
public class FhirResourceDaoDstu3UpdateTest extends BaseJpaDstu3Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3UpdateTest.class);
@Test
public void testReCreateMatchResource() {
CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl("http://foo");
IIdType id = myCodeSystemDao.create(codeSystem).getId().toUnqualifiedVersionless();
myCodeSystemDao.delete(id);
codeSystem = new CodeSystem();
codeSystem.setUrl("http://foo");
myCodeSystemDao.update(codeSystem, "Patient?name=FAM").getId().toUnqualifiedVersionless();
}
@Test
public void testCreateAndUpdateWithoutRequest() throws Exception {
String methodName = "testUpdateByUrl";

View File

@ -28,6 +28,21 @@ import ca.uhn.fhir.util.TestUtil;
public class FhirResourceDaoR4UpdateTest extends BaseJpaR4Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4UpdateTest.class);
@Test
public void testReCreateMatchResource() {
CodeSystem codeSystem = new CodeSystem();
codeSystem.setUrl("http://foo");
IIdType id = myCodeSystemDao.create(codeSystem).getId().toUnqualifiedVersionless();
myCodeSystemDao.delete(id);
codeSystem = new CodeSystem();
codeSystem.setUrl("http://foo");
myCodeSystemDao.update(codeSystem, "Patient?name=FAM").getId().toUnqualifiedVersionless();
}
@Test
public void testCreateAndUpdateWithoutRequest() throws Exception {
String methodName = "testUpdateByUrl";

View File

@ -1,28 +1,7 @@
package org.hl7.fhir.dstu3.hapi.validation;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.zip.GZIPInputStream;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ResultSeverityEnum;
import ca.uhn.fhir.validation.SingleValidationMessage;
@ -32,65 +11,185 @@ import org.apache.commons.io.IOUtils;
import org.hl7.fhir.dstu3.hapi.ctx.HapiWorkerContext;
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport.CodeValidationResult;
import org.hl7.fhir.dstu3.model.Base;
import org.hl7.fhir.dstu3.model.BooleanType;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.dstu3.model.CodeSystem;
import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.dstu3.model.CodeType;
import org.hl7.fhir.dstu3.model.ContactPoint;
import org.hl7.fhir.dstu3.model.Extension;
import org.hl7.fhir.dstu3.model.Observation;
import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.RelatedPerson;
import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.dstu3.model.StructureDefinition;
import org.hl7.fhir.dstu3.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.dstu3.model.ValueSet;
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
import org.hl7.fhir.dstu3.utils.FHIRPathEngine;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.*;
import org.junit.rules.TestRule;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.util.TestUtil;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.zip.GZIPInputStream;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class FhirInstanceValidatorDstu3Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirInstanceValidatorDstu3Test.class);
private static DefaultProfileValidationSupport myDefaultValidationSupport = new DefaultProfileValidationSupport();
private static FhirContext ourCtx = FhirContext.forDstu3();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirInstanceValidatorDstu3Test.class);
private FhirInstanceValidator myInstanceVal;
private IValidationSupport myMockSupport;
private Map<String, ValueSetExpansionComponent> mySupportedCodeSystemsForExpansion;
private FhirValidator myVal;
private ArrayList<String> myValidConcepts;
private Set<String> myValidSystems = new HashSet<String>();
@Rule
public TestRule watcher = new TestWatcher() {
protected void starting(Description description) {
ourLog.info("Starting test: " + description.getMethodName());
}
};
private FhirInstanceValidator myInstanceVal;
private IValidationSupport myMockSupport;
private Map<String, ValueSetExpansionComponent> mySupportedCodeSystemsForExpansion;
private FhirValidator myVal;
private ArrayList<String> myValidConcepts;
private Set<String> myValidSystems = new HashSet<String>();
private void addValidConcept(String theSystem, String theCode) {
myValidSystems.add(theSystem);
myValidConcepts.add(theSystem + "___" + theCode);
}
@SuppressWarnings("unchecked")
@Before
public void before() {
myVal = ourCtx.newValidator();
myVal.setValidateAgainstStandardSchema(false);
myVal.setValidateAgainstStandardSchematron(false);
myMockSupport = mock(IValidationSupport.class);
ValidationSupportChain validationSupport = new ValidationSupportChain(myMockSupport, myDefaultValidationSupport);
myInstanceVal = new FhirInstanceValidator(validationSupport);
myVal.registerValidatorModule(myInstanceVal);
mySupportedCodeSystemsForExpansion = new HashMap<String, ValueSet.ValueSetExpansionComponent>();
myValidConcepts = new ArrayList<String>();
when(myMockSupport.expandValueSet(any(FhirContext.class), any(ConceptSetComponent.class))).thenAnswer(new Answer<ValueSetExpansionComponent>() {
@Override
public ValueSetExpansionComponent answer(InvocationOnMock theInvocation) throws Throwable {
ConceptSetComponent arg = (ConceptSetComponent) theInvocation.getArguments()[0];
ValueSetExpansionComponent retVal = mySupportedCodeSystemsForExpansion.get(arg.getSystem());
if (retVal == null) {
retVal = myDefaultValidationSupport.expandValueSet(any(FhirContext.class), arg);
}
ourLog.debug("expandValueSet({}) : {}", new Object[]{theInvocation.getArguments()[0], retVal});
return retVal;
}
});
when(myMockSupport.isCodeSystemSupported(any(FhirContext.class), any(String.class))).thenAnswer(new Answer<Boolean>() {
@Override
public Boolean answer(InvocationOnMock theInvocation) throws Throwable {
boolean retVal = myValidSystems.contains(theInvocation.getArguments()[1]);
ourLog.debug("isCodeSystemSupported({}) : {}", new Object[]{theInvocation.getArguments()[1], retVal});
return retVal;
}
});
when(myMockSupport.fetchResource(any(FhirContext.class), any(Class.class), any(String.class))).thenAnswer(new Answer<IBaseResource>() {
@Override
public IBaseResource answer(InvocationOnMock theInvocation) throws Throwable {
IBaseResource retVal;
String id = (String) theInvocation.getArguments()[2];
if ("Questionnaire/q_jon".equals(id)) {
retVal = ourCtx.newJsonParser().parseResource(IOUtils.toString(FhirInstanceValidatorDstu3Test.class.getResourceAsStream("/q_jon.json")));
} else {
retVal = myDefaultValidationSupport.fetchResource((FhirContext) theInvocation.getArguments()[0], (Class<IBaseResource>) theInvocation.getArguments()[1], id);
}
ourLog.debug("fetchResource({}, {}) : {}", new Object[]{theInvocation.getArguments()[1], id, retVal});
return retVal;
}
});
when(myMockSupport.validateCode(any(FhirContext.class), any(String.class), any(String.class), any(String.class))).thenAnswer(new Answer<CodeValidationResult>() {
@Override
public CodeValidationResult answer(InvocationOnMock theInvocation) throws Throwable {
FhirContext ctx = (FhirContext) theInvocation.getArguments()[0];
String system = (String) theInvocation.getArguments()[1];
String code = (String) theInvocation.getArguments()[2];
CodeValidationResult retVal;
if (myValidConcepts.contains(system + "___" + code)) {
retVal = new CodeValidationResult(new ConceptDefinitionComponent(new CodeType(code)));
} else {
retVal = myDefaultValidationSupport.validateCode(ctx, system, code, (String) theInvocation.getArguments()[2]);
}
ourLog.debug("validateCode({}, {}, {}) : {}", new Object[]{system, code, (String) theInvocation.getArguments()[2], retVal});
return retVal;
}
});
when(myMockSupport.fetchCodeSystem(any(FhirContext.class), any(String.class))).thenAnswer(new Answer<CodeSystem>() {
@Override
public CodeSystem answer(InvocationOnMock theInvocation) throws Throwable {
CodeSystem retVal = myDefaultValidationSupport.fetchCodeSystem((FhirContext) theInvocation.getArguments()[0], (String) theInvocation.getArguments()[1]);
ourLog.debug("fetchCodeSystem({}) : {}", new Object[]{(String) theInvocation.getArguments()[1], retVal});
return retVal;
}
});
when(myMockSupport.fetchStructureDefinition(any(FhirContext.class), any(String.class))).thenAnswer(new Answer<StructureDefinition>() {
@Override
public StructureDefinition answer(InvocationOnMock theInvocation) throws Throwable {
StructureDefinition retVal = myDefaultValidationSupport.fetchStructureDefinition((FhirContext) theInvocation.getArguments()[0], (String) theInvocation.getArguments()[1]);
ourLog.debug("fetchStructureDefinition({}) : {}", new Object[]{(String) theInvocation.getArguments()[1], retVal});
return retVal;
}
});
when(myMockSupport.fetchAllStructureDefinitions(any(FhirContext.class))).thenAnswer(new Answer<List<StructureDefinition>>() {
@Override
public List<StructureDefinition> answer(InvocationOnMock theInvocation) throws Throwable {
List<StructureDefinition> retVal = myDefaultValidationSupport.fetchAllStructureDefinitions((FhirContext) theInvocation.getArguments()[0]);
ourLog.debug("fetchAllStructureDefinitions()", new Object[]{});
return retVal;
}
});
}
private Object defaultString(Integer theLocationLine) {
return theLocationLine != null ? theLocationLine.toString() : "";
}
private List<SingleValidationMessage> logResultsAndReturnAll(ValidationResult theOutput) {
List<SingleValidationMessage> retVal = new ArrayList<SingleValidationMessage>();
int index = 0;
for (SingleValidationMessage next : theOutput.getMessages()) {
ourLog.info("Result {}: {} - {}:{} {} - {}",
new Object[]{index, next.getSeverity(), defaultString(next.getLocationLine()), defaultString(next.getLocationCol()), next.getLocationString(), next.getMessage()});
index++;
retVal.add(next);
}
return retVal;
}
private List<SingleValidationMessage> logResultsAndReturnNonInformationalOnes(ValidationResult theOutput) {
List<SingleValidationMessage> retVal = new ArrayList<SingleValidationMessage>();
int index = 0;
for (SingleValidationMessage next : theOutput.getMessages()) {
ourLog.info("Result {}: {} - {} - {}", new Object[]{index, next.getSeverity(), next.getLocationString(), next.getMessage()});
index++;
if (next.getSeverity() != ResultSeverityEnum.INFORMATION) {
retVal.add(next);
}
}
return retVal;
}
/**
* See #531
*/
@ -120,46 +219,33 @@ public class FhirInstanceValidatorDstu3Test {
}
/**
* See #370
*/
@Test
public void testValidateRelatedPerson() {
public void testIsNoTerminologyChecks() {
assertFalse(myInstanceVal.isNoTerminologyChecks());
myInstanceVal.setNoTerminologyChecks(true);
assertTrue(myInstanceVal.isNoTerminologyChecks());
}
/*
* Try with a code that is in http://hl7.org/fhir/ValueSet/relatedperson-relationshiptype
* and therefore should validate
*/
RelatedPerson rp = new RelatedPerson();
rp.getPatient().setReference("Patient/1");
rp.getRelationship().addCoding().setSystem("http://hl7.org/fhir/v2/0131").setCode("c");
@Test
public void testValidateBigRawJsonResource() throws Exception {
InputStream stream = FhirInstanceValidatorDstu3Test.class.getResourceAsStream("/conformance.json.gz");
stream = new GZIPInputStream(stream);
String input = IOUtils.toString(stream);
ValidationResult results = myVal.validateWithResult(rp);
List<SingleValidationMessage> outcome = logResultsAndReturnNonInformationalOnes(results);
assertThat(outcome, empty());
long start = System.currentTimeMillis();
ValidationResult output = null;
int passes = 1;
for (int i = 0; i < passes; i++) {
ourLog.info("Pass {}", i + 1);
output = myVal.validateWithResult(input);
}
/*
* Code system is case insensitive, so try with capital C
*/
rp = new RelatedPerson();
rp.getPatient().setReference("Patient/1");
rp.getRelationship().addCoding().setSystem("http://hl7.org/fhir/v2/0131").setCode("C");
long delay = System.currentTimeMillis() - start;
long per = delay / passes;
results = myVal.validateWithResult(rp);
outcome = logResultsAndReturnNonInformationalOnes(results);
assertThat(outcome, empty());
/*
* Now a bad code
*/
rp = new RelatedPerson();
rp.getPatient().setReference("Patient/1");
rp.getRelationship().addCoding().setSystem("http://hl7.org/fhir/v2/0131").setCode("GAGAGAGA");
results = myVal.validateWithResult(rp);
outcome = logResultsAndReturnNonInformationalOnes(results);
assertThat(outcome, not(empty()));
logResultsAndReturnAll(output);
ourLog.info("Took {} ms -- {}ms / pass", delay, per);
}
@Test
@ -197,21 +283,6 @@ public class FhirInstanceValidatorDstu3Test {
ourLog.info("Validated the following:\n{}", ids);
}
/**
* FHIRPathEngine was throwing Error...
*/
@Test
public void testValidateCrucibleCarePlan() throws Exception {
org.hl7.fhir.dstu3.model.Bundle bundle;
String name = "profiles-resources";
ourLog.info("Uploading " + name);
String vsContents;
vsContents = IOUtils.toString(FhirInstanceValidatorDstu3Test.class.getResourceAsStream("/crucible-condition.xml"), "UTF-8");
ValidationResult output = myVal.validateWithResult(vsContents);
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
}
@Test
@Ignore
public void testValidateBundleWithObservations() throws Exception {
@ -241,6 +312,21 @@ public class FhirInstanceValidatorDstu3Test {
}
/**
* FHIRPathEngine was throwing Error...
*/
@Test
public void testValidateCrucibleCarePlan() throws Exception {
org.hl7.fhir.dstu3.model.Bundle bundle;
String name = "profiles-resources";
ourLog.info("Uploading " + name);
String vsContents;
vsContents = IOUtils.toString(FhirInstanceValidatorDstu3Test.class.getResourceAsStream("/crucible-condition.xml"), "UTF-8");
ValidationResult output = myVal.validateWithResult(vsContents);
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
}
@Test
public void testValidateDocument() throws Exception {
String vsContents = IOUtils.toString(FhirInstanceValidatorDstu3Test.class.getResourceAsStream("/sample-document.xml"), "UTF-8");
@ -250,184 +336,6 @@ public class FhirInstanceValidatorDstu3Test {
assertTrue(output.isSuccessful());
}
/**
* A reference with only an identifier should be valid
*/
@Test
public void testValidateReferenceWithIdentifierValid() throws Exception {
Patient p = new Patient();
p.getManagingOrganization().getIdentifier().setSystem("http://acme.org");
p.getManagingOrganization().getIdentifier().setValue("foo");
ValidationResult output = myVal.validateWithResult(p);
List<SingleValidationMessage> nonInfo = logResultsAndReturnNonInformationalOnes(output);
assertThat(nonInfo, empty());
}
/**
* A reference with only an identifier should be valid
*/
@Test
public void testValidateReferenceWithDisplayValid() throws Exception {
Patient p = new Patient();
p.getManagingOrganization().setDisplay("HELLO");
ValidationResult output = myVal.validateWithResult(p);
List<SingleValidationMessage> nonInfo = logResultsAndReturnNonInformationalOnes(output);
assertThat(nonInfo, empty());
}
@SuppressWarnings("unchecked")
@Before
public void before() {
myVal = ourCtx.newValidator();
myVal.setValidateAgainstStandardSchema(false);
myVal.setValidateAgainstStandardSchematron(false);
myMockSupport = mock(IValidationSupport.class);
ValidationSupportChain validationSupport = new ValidationSupportChain(myMockSupport, myDefaultValidationSupport);
myInstanceVal = new FhirInstanceValidator(validationSupport);
myVal.registerValidatorModule(myInstanceVal);
mySupportedCodeSystemsForExpansion = new HashMap<String, ValueSet.ValueSetExpansionComponent>();
myValidConcepts = new ArrayList<String>();
when(myMockSupport.expandValueSet(any(FhirContext.class), any(ConceptSetComponent.class))).thenAnswer(new Answer<ValueSetExpansionComponent>() {
@Override
public ValueSetExpansionComponent answer(InvocationOnMock theInvocation) throws Throwable {
ConceptSetComponent arg = (ConceptSetComponent) theInvocation.getArguments()[0];
ValueSetExpansionComponent retVal = mySupportedCodeSystemsForExpansion.get(arg.getSystem());
if (retVal == null) {
retVal = myDefaultValidationSupport.expandValueSet(any(FhirContext.class), arg);
}
ourLog.debug("expandValueSet({}) : {}", new Object[] { theInvocation.getArguments()[0], retVal });
return retVal;
}
});
when(myMockSupport.isCodeSystemSupported(any(FhirContext.class), any(String.class))).thenAnswer(new Answer<Boolean>() {
@Override
public Boolean answer(InvocationOnMock theInvocation) throws Throwable {
boolean retVal = myValidSystems.contains(theInvocation.getArguments()[1]);
ourLog.debug("isCodeSystemSupported({}) : {}", new Object[] { theInvocation.getArguments()[1], retVal });
return retVal;
}
});
when(myMockSupport.fetchResource(any(FhirContext.class), any(Class.class), any(String.class))).thenAnswer(new Answer<IBaseResource>() {
@Override
public IBaseResource answer(InvocationOnMock theInvocation) throws Throwable {
IBaseResource retVal;
String id = (String) theInvocation.getArguments()[2];
if ("Questionnaire/q_jon".equals(id)) {
retVal = ourCtx.newJsonParser().parseResource(IOUtils.toString(FhirInstanceValidatorDstu3Test.class.getResourceAsStream("/q_jon.json")));
} else {
retVal = myDefaultValidationSupport.fetchResource((FhirContext) theInvocation.getArguments()[0], (Class<IBaseResource>) theInvocation.getArguments()[1], id);
}
ourLog.debug("fetchResource({}, {}) : {}", new Object[] { theInvocation.getArguments()[1], id, retVal });
return retVal;
}
});
when(myMockSupport.validateCode(any(FhirContext.class), any(String.class), any(String.class), any(String.class))).thenAnswer(new Answer<CodeValidationResult>() {
@Override
public CodeValidationResult answer(InvocationOnMock theInvocation) throws Throwable {
FhirContext ctx = (FhirContext) theInvocation.getArguments()[0];
String system = (String) theInvocation.getArguments()[1];
String code = (String) theInvocation.getArguments()[2];
CodeValidationResult retVal;
if (myValidConcepts.contains(system + "___" + code)) {
retVal = new CodeValidationResult(new ConceptDefinitionComponent(new CodeType(code)));
} else {
retVal = myDefaultValidationSupport.validateCode(ctx, system, code, (String) theInvocation.getArguments()[2]);
}
ourLog.debug("validateCode({}, {}, {}) : {}", new Object[] { system, code, (String) theInvocation.getArguments()[2], retVal });
return retVal;
}
});
when(myMockSupport.fetchCodeSystem(any(FhirContext.class), any(String.class))).thenAnswer(new Answer<CodeSystem>() {
@Override
public CodeSystem answer(InvocationOnMock theInvocation) throws Throwable {
CodeSystem retVal = myDefaultValidationSupport.fetchCodeSystem((FhirContext) theInvocation.getArguments()[0], (String) theInvocation.getArguments()[1]);
ourLog.debug("fetchCodeSystem({}) : {}", new Object[] { (String) theInvocation.getArguments()[1], retVal });
return retVal;
}
});
when(myMockSupport.fetchStructureDefinition(any(FhirContext.class), any(String.class))).thenAnswer(new Answer<StructureDefinition>() {
@Override
public StructureDefinition answer(InvocationOnMock theInvocation) throws Throwable {
StructureDefinition retVal = myDefaultValidationSupport.fetchStructureDefinition((FhirContext) theInvocation.getArguments()[0], (String) theInvocation.getArguments()[1]);
ourLog.debug("fetchStructureDefinition({}) : {}", new Object[] { (String) theInvocation.getArguments()[1], retVal });
return retVal;
}
});
when(myMockSupport.fetchAllStructureDefinitions(any(FhirContext.class))).thenAnswer(new Answer<List<StructureDefinition>>() {
@Override
public List<StructureDefinition> answer(InvocationOnMock theInvocation) throws Throwable {
List<StructureDefinition> retVal = myDefaultValidationSupport.fetchAllStructureDefinitions((FhirContext) theInvocation.getArguments()[0]);
ourLog.debug("fetchAllStructureDefinitions()", new Object[] {});
return retVal;
}
});
}
private Object defaultString(Integer theLocationLine) {
return theLocationLine != null ? theLocationLine.toString() : "";
}
private List<SingleValidationMessage> logResultsAndReturnAll(ValidationResult theOutput) {
List<SingleValidationMessage> retVal = new ArrayList<SingleValidationMessage>();
int index = 0;
for (SingleValidationMessage next : theOutput.getMessages()) {
ourLog.info("Result {}: {} - {}:{} {} - {}",
new Object[] { index, next.getSeverity(), defaultString(next.getLocationLine()), defaultString(next.getLocationCol()), next.getLocationString(), next.getMessage() });
index++;
retVal.add(next);
}
return retVal;
}
private List<SingleValidationMessage> logResultsAndReturnNonInformationalOnes(ValidationResult theOutput) {
List<SingleValidationMessage> retVal = new ArrayList<SingleValidationMessage>();
int index = 0;
for (SingleValidationMessage next : theOutput.getMessages()) {
ourLog.info("Result {}: {} - {} - {}", new Object[] { index, next.getSeverity(), next.getLocationString(), next.getMessage() });
index++;
if (next.getSeverity() != ResultSeverityEnum.INFORMATION) {
retVal.add(next);
}
}
return retVal;
}
@Test
public void testValidateBigRawJsonResource() throws Exception {
InputStream stream = FhirInstanceValidatorDstu3Test.class.getResourceAsStream("/conformance.json.gz");
stream = new GZIPInputStream(stream);
String input = IOUtils.toString(stream);
long start = System.currentTimeMillis();
ValidationResult output = null;
int passes = 1;
for (int i = 0; i < passes; i++) {
ourLog.info("Pass {}", i + 1);
output = myVal.validateWithResult(input);
}
long delay = System.currentTimeMillis() - start;
long per = delay / passes;
logResultsAndReturnAll(output);
ourLog.info("Took {} ms -- {}ms / pass", delay, per);
}
@Test
public void testValidateQuestionnaireResponse() throws IOException {
String input = IOUtils.toString(FhirInstanceValidatorDstu3Test.class.getResourceAsStream("/qr_jon.xml"));
@ -448,6 +356,40 @@ public class FhirInstanceValidatorDstu3Test {
assertEquals(output.toString(), 0, output.getMessages().size());
}
@Test
public void testValidateRawJsonResourceBadAttributes() {
//@formatter:off
String input =
"{" +
"\"resourceType\":\"Patient\"," +
"\"id\":\"123\"," +
"\"foo\":\"123\"" +
"}";
//@formatter:on
ValidationResult output = myVal.validateWithResult(input);
assertEquals(output.toString(), 1, output.getMessages().size());
ourLog.info(output.getMessages().get(0).getLocationString());
ourLog.info(output.getMessages().get(0).getMessage());
assertEquals("/Patient", output.getMessages().get(0).getLocationString());
assertEquals("Unrecognised property '@foo'", output.getMessages().get(0).getMessage());
}
@Test
public void testValidateRawJsonResourceFromExamples() throws Exception {
// @formatter:off
String input = IOUtils.toString(FhirInstanceValidator.class.getResourceAsStream("/testscript-search.json"));
// @formatter:on
ValidationResult output = myVal.validateWithResult(input);
logResultsAndReturnNonInformationalOnes(output);
// assertEquals(output.toString(), 1, output.getMessages().size());
// ourLog.info(output.getMessages().get(0).getLocationString());
// ourLog.info(output.getMessages().get(0).getMessage());
// assertEquals("/foo", output.getMessages().get(0).getLocationString());
// assertEquals("Element is unknown or does not match any slice", output.getMessages().get(0).getMessage());
}
@Test
public void testValidateRawJsonResourceWithUnknownExtension() {
@ -515,65 +457,6 @@ public class FhirInstanceValidatorDstu3Test {
assertEquals(ResultSeverityEnum.ERROR, output.getMessages().get(0).getSeverity());
}
@Test
public void testValidateRawXmlWithMissingRootNamespace() {
//@formatter:off
String input = ""
+ "<Patient>"
+ " <text>"
+ " <status value=\"generated\"/>"
+ " <div xmlns=\"http://www.w3.org/1999/xhtml\">Some narrative</div>"
+ " </text>"
+ " <name>"
+ " <use value=\"official\"/>"
+ " <family value=\"Doe\"/>"
+ " <given value=\"John\"/>"
+ " </name>"
+ " <gender value=\"male\"/>"
+ " <birthDate value=\"1974-12-25\"/>"
+ "</Patient>";
//@formatter:on
ValidationResult output = myVal.validateWithResult(input);
assertEquals(output.toString(), 1, output.getMessages().size());
assertEquals("This cannot be parsed as a FHIR object (no namespace)", output.getMessages().get(0).getMessage());
ourLog.info(output.getMessages().get(0).getLocationString());
}
@Test
public void testValidateRawJsonResourceBadAttributes() {
//@formatter:off
String input =
"{" +
"\"resourceType\":\"Patient\"," +
"\"id\":\"123\"," +
"\"foo\":\"123\"" +
"}";
//@formatter:on
ValidationResult output = myVal.validateWithResult(input);
assertEquals(output.toString(), 1, output.getMessages().size());
ourLog.info(output.getMessages().get(0).getLocationString());
ourLog.info(output.getMessages().get(0).getMessage());
assertEquals("/Patient", output.getMessages().get(0).getLocationString());
assertEquals("Unrecognised property '@foo'", output.getMessages().get(0).getMessage());
}
@Test
public void testValidateRawJsonResourceFromExamples() throws Exception {
// @formatter:off
String input = IOUtils.toString(FhirInstanceValidator.class.getResourceAsStream("/testscript-search.json"));
// @formatter:on
ValidationResult output = myVal.validateWithResult(input);
logResultsAndReturnNonInformationalOnes(output);
// assertEquals(output.toString(), 1, output.getMessages().size());
// ourLog.info(output.getMessages().get(0).getLocationString());
// ourLog.info(output.getMessages().get(0).getMessage());
// assertEquals("/foo", output.getMessages().get(0).getLocationString());
// assertEquals("Element is unknown or does not match any slice", output.getMessages().get(0).getMessage());
}
@Test
public void testValidateRawXmlResource() {
// @formatter:off
@ -584,6 +467,21 @@ public class FhirInstanceValidatorDstu3Test {
assertEquals(output.toString(), 0, output.getMessages().size());
}
@Test
public void testValidateRawXmlResourceBadAttributes() {
//@formatter:off
String input = "<Patient xmlns=\"http://hl7.org/fhir\">" + "<id value=\"123\"/>" + "<foo value=\"222\"/>"
+ "</Patient>";
//@formatter:on
ValidationResult output = myVal.validateWithResult(input);
assertEquals(output.toString(), 1, output.getMessages().size());
ourLog.info(output.getMessages().get(0).getLocationString());
ourLog.info(output.getMessages().get(0).getMessage());
assertEquals("/f:Patient", output.getMessages().get(0).getLocationString());
assertEquals("Undefined element 'foo\"", output.getMessages().get(0).getMessage());
}
@Test
public void testValidateRawXmlResourceWithEmptyPrimitive() {
// @formatter:off
@ -599,26 +497,26 @@ public class FhirInstanceValidatorDstu3Test {
@Test
public void testValidateRawXmlResourceWithPrimitiveContainingOnlyAnExtension() {
// @formatter:off
String input = "<ActivityDefinition xmlns=\"http://hl7.org/fhir\">\n" +
" <id value=\"referralToMentalHealthCare\"/>\n" +
" <status value=\"draft\"/>\n" +
" <description value=\"refer to primary care mental-health integrated care program for evaluation and treatment of mental health conditions now\"/>\n" +
" <code>\n" +
" <coding>\n" +
" <!-- Error: Connection to http://localhost:960 refused -->\n" +
" <!--<system value=\"http://snomed.info/sct\"/>-->\n" +
" <code value=\"306206005\"/>\n" +
" </coding>\n" +
" </code>\n" +
" <!-- Specifying this this way results in a null reference exception in the validator -->\n" +
" <timingTiming>\n" +
" <event>\n" +
" <extension url=\"http://fhir.org/cql-expression\">\n" +
" <valueString value=\"Now()\"/>\n" +
" </extension>\n" +
" </event>\n" +
" </timingTiming>\n" +
" </ActivityDefinition>";
String input = "<ActivityDefinition xmlns=\"http://hl7.org/fhir\">\n" +
" <id value=\"referralToMentalHealthCare\"/>\n" +
" <status value=\"draft\"/>\n" +
" <description value=\"refer to primary care mental-health integrated care program for evaluation and treatment of mental health conditions now\"/>\n" +
" <code>\n" +
" <coding>\n" +
" <!-- Error: Connection to http://localhost:960 refused -->\n" +
" <!--<system value=\"http://snomed.info/sct\"/>-->\n" +
" <code value=\"306206005\"/>\n" +
" </coding>\n" +
" </code>\n" +
" <!-- Specifying this this way results in a null reference exception in the validator -->\n" +
" <timingTiming>\n" +
" <event>\n" +
" <extension url=\"http://fhir.org/cql-expression\">\n" +
" <valueString value=\"Now()\"/>\n" +
" </extension>\n" +
" </event>\n" +
" </timingTiming>\n" +
" </ActivityDefinition>";
// @formatter:on
ValidationResult output = myVal.validateWithResult(input);
@ -627,18 +525,97 @@ public class FhirInstanceValidatorDstu3Test {
}
@Test
public void testValidateRawXmlResourceBadAttributes() {
public void testValidateRawXmlWithMissingRootNamespace() {
//@formatter:off
String input = "<Patient xmlns=\"http://hl7.org/fhir\">" + "<id value=\"123\"/>" + "<foo value=\"222\"/>"
+ "</Patient>";
//@formatter:on
String input = ""
+ "<Patient>"
+ " <text>"
+ " <status value=\"generated\"/>"
+ " <div xmlns=\"http://www.w3.org/1999/xhtml\">Some narrative</div>"
+ " </text>"
+ " <name>"
+ " <use value=\"official\"/>"
+ " <family value=\"Doe\"/>"
+ " <given value=\"John\"/>"
+ " </name>"
+ " <gender value=\"male\"/>"
+ " <birthDate value=\"1974-12-25\"/>"
+ "</Patient>";
//@formatter:on
ValidationResult output = myVal.validateWithResult(input);
assertEquals(output.toString(), 1, output.getMessages().size());
assertEquals("This cannot be parsed as a FHIR object (no namespace)", output.getMessages().get(0).getMessage());
ourLog.info(output.getMessages().get(0).getLocationString());
ourLog.info(output.getMessages().get(0).getMessage());
assertEquals("/f:Patient", output.getMessages().get(0).getLocationString());
assertEquals("Undefined element 'foo\"", output.getMessages().get(0).getMessage());
}
/**
* A reference with only an identifier should be valid
*/
@Test
public void testValidateReferenceWithDisplayValid() throws Exception {
Patient p = new Patient();
p.getManagingOrganization().setDisplay("HELLO");
ValidationResult output = myVal.validateWithResult(p);
List<SingleValidationMessage> nonInfo = logResultsAndReturnNonInformationalOnes(output);
assertThat(nonInfo, empty());
}
/**
* A reference with only an identifier should be valid
*/
@Test
public void testValidateReferenceWithIdentifierValid() throws Exception {
Patient p = new Patient();
p.getManagingOrganization().getIdentifier().setSystem("http://acme.org");
p.getManagingOrganization().getIdentifier().setValue("foo");
ValidationResult output = myVal.validateWithResult(p);
List<SingleValidationMessage> nonInfo = logResultsAndReturnNonInformationalOnes(output);
assertThat(nonInfo, empty());
}
/**
* See #370
*/
@Test
public void testValidateRelatedPerson() {
/*
* Try with a code that is in http://hl7.org/fhir/ValueSet/relatedperson-relationshiptype
* and therefore should validate
*/
RelatedPerson rp = new RelatedPerson();
rp.getPatient().setReference("Patient/1");
rp.getRelationship().addCoding().setSystem("http://hl7.org/fhir/v2/0131").setCode("c");
ValidationResult results = myVal.validateWithResult(rp);
List<SingleValidationMessage> outcome = logResultsAndReturnNonInformationalOnes(results);
assertThat(outcome, empty());
/*
* Code system is case insensitive, so try with capital C
*/
rp = new RelatedPerson();
rp.getPatient().setReference("Patient/1");
rp.getRelationship().addCoding().setSystem("http://hl7.org/fhir/v2/0131").setCode("C");
results = myVal.validateWithResult(rp);
outcome = logResultsAndReturnNonInformationalOnes(results);
assertThat(outcome, empty());
/*
* Now a bad code
*/
rp = new RelatedPerson();
rp.getPatient().setReference("Patient/1");
rp.getRelationship().addCoding().setSystem("http://hl7.org/fhir/v2/0131").setCode("GAGAGAGA");
results = myVal.validateWithResult(rp);
outcome = logResultsAndReturnNonInformationalOnes(results);
assertThat(outcome, not(empty()));
}
@Test
@ -730,19 +707,19 @@ public class FhirInstanceValidatorDstu3Test {
@Test
public void testValidateResourceWithDefaultValuesetBadCode() {
//@formatter:off
String input =
String input =
"<Observation xmlns=\"http://hl7.org/fhir\">\n" +
" <status value=\"notvalidcode\"/>\n" +
" <code>\n" +
" <text value=\"No code here!\"/>\n" +
" </code>\n" +
"</Observation>";
" <status value=\"notvalidcode\"/>\n" +
" <code>\n" +
" <text value=\"No code here!\"/>\n" +
" </code>\n" +
"</Observation>";
//@formatter:on
ValidationResult output = myVal.validateWithResult(input);
logResultsAndReturnAll(output);
assertEquals(
"The value provided ('notvalidcode') is not in the value set http://hl7.org/fhir/ValueSet/observation-status (http://hl7.org/fhir/ValueSet/observation-status, and a code is required from this value set) (error message = Unknown code[notvalidcode] in system[null])",
output.getMessages().get(0).getMessage());
"The value provided ('notvalidcode') is not in the value set http://hl7.org/fhir/ValueSet/observation-status (http://hl7.org/fhir/ValueSet/observation-status, and a code is required from this value set) (error message = Unknown code[notvalidcode] in system[null])",
output.getMessages().get(0).getMessage());
}
@Test
@ -760,6 +737,23 @@ public class FhirInstanceValidatorDstu3Test {
}
@Test
public void testValidateResourceWithExampleBindingCodeValidationFailingNonLoinc() {
Observation input = new Observation();
myInstanceVal.setValidationSupport(myMockSupport);
addValidConcept("http://acme.org", "12345");
input.setStatus(ObservationStatus.FINAL);
input.getCode().addCoding().setSystem("http://acme.org").setCode("9988877");
ValidationResult output = myVal.validateWithResult(input);
List<SingleValidationMessage> errors = logResultsAndReturnAll(output);
assertThat(errors.toString(), errors.size(), greaterThan(0));
assertEquals("Unknown code: http://acme.org / 9988877", errors.get(0).getMessage());
}
@Test
public void testValidateResourceWithExampleBindingCodeValidationPassingLoinc() {
Observation input = new Observation();
@ -810,23 +804,6 @@ public class FhirInstanceValidatorDstu3Test {
assertEquals(errors.toString(), 0, errors.size());
}
@Test
public void testValidateResourceWithExampleBindingCodeValidationFailingNonLoinc() {
Observation input = new Observation();
myInstanceVal.setValidationSupport(myMockSupport);
addValidConcept("http://acme.org", "12345");
input.setStatus(ObservationStatus.FINAL);
input.getCode().addCoding().setSystem("http://acme.org").setCode("9988877");
ValidationResult output = myVal.validateWithResult(input);
List<SingleValidationMessage> errors = logResultsAndReturnAll(output);
assertThat(errors.toString(), errors.size(), greaterThan(0));
assertEquals("Unknown code: http://acme.org / 9988877", errors.get(0).getMessage());
}
@Test
public void testValidateResourceWithValuesetExpansionBad() {
@ -838,8 +815,8 @@ public class FhirInstanceValidatorDstu3Test {
assertEquals(1, all.size());
assertEquals("Patient.identifier.type", all.get(0).getLocationString());
assertEquals(
"None of the codes provided are in the value set http://hl7.org/fhir/ValueSet/identifier-type (http://hl7.org/fhir/ValueSet/identifier-type, and a code should come from this value set unless it has no suitable code) (codes = http://example.com/foo/bar#bar)",
all.get(0).getMessage());
"None of the codes provided are in the value set http://hl7.org/fhir/ValueSet/identifier-type (http://hl7.org/fhir/ValueSet/identifier-type, and a code should come from this value set unless it has no suitable code) (codes = http://example.com/foo/bar#bar)",
all.get(0).getMessage());
assertEquals(ResultSeverityEnum.WARNING, all.get(0).getSeverity());
}
@ -854,13 +831,6 @@ public class FhirInstanceValidatorDstu3Test {
assertEquals(0, all.size());
}
@Test
public void testIsNoTerminologyChecks() {
assertFalse(myInstanceVal.isNoTerminologyChecks());
myInstanceVal.setNoTerminologyChecks(true);
assertTrue(myInstanceVal.isNoTerminologyChecks());
}
@Test
@Ignore
public void testValidateStructureDefinition() throws IOException {
@ -874,6 +844,17 @@ public class FhirInstanceValidatorDstu3Test {
ourLog.info(output.getMessages().get(0).getMessage());
}
@Test
public void testValueWithWhitespace() throws IOException {
String input = IOUtils.toString(FhirInstanceValidatorDstu3Test.class.getResourceAsStream("/dstu3-rick-test.json"), Charsets.UTF_8);
ValidationResult results = myVal.validateWithResult(input);
List<SingleValidationMessage> outcome = logResultsAndReturnNonInformationalOnes(results);
assertEquals(1, outcome.size());
assertThat(outcome.toString(), containsString("value should not start or finish with whitespace"));
}
@AfterClass
public static void afterClassClearContext() {
myDefaultValidationSupport.flush();

View File

@ -0,0 +1,61 @@
{
"resourceType": "CommunicationRequest",
"id": "Christol0808",
"meta": {
"versionId": "1",
"lastUpdated": "2017-09-09T13:40:35.438-04:00"
},
"text": {
"status": "generated",
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\">Request for Encounter 08082017 Report</div>"
},
"extension": [
{
"url": "http://hl7.org/fhir/us/attachments/StructureDefinition/attachment-type",
"valueCodeableConcept": {
"coding": [
{
"system": "http://loinc.org",
"code": "34133-1",
"display": "Summarization of Encounter Note 08082017"
}
]
}
}
],
"identifier": [
{
"system": "http://www.jurisdiction.com/insurer/123456",
"value": "AnthemChristol08082017",
"_value": {
"fhir_comments": [
" this is the value to which the response will refer "
]
}
}
],
"basedOn": [
{
"reference": "Claim/good-health-claim-1"
}
],
"status": "active",
"subject": {
"reference": "Patient/good-health-patient-1"
},
"recipient": [
{
"reference": "Organization/good-health"
}
],
"payload": [
{
"contentString": "Please provide the summarization of encounter note. "
}
],
"occurrenceDateTime": "2017-09-09T08:01:10-08:00",
"authoredOn": "2017-09-09T08:01:10-08:00",
"sender": {
"reference": "Organization/example-payer"
}
}

View File

@ -361,6 +361,15 @@
the returned
<![CDATA[<code>Location</code>]]> header value as well
</action>
<action type="add">
A new flag has been add to the CLI upload-definitions command
"-e" which allows skipping particular resources
</action>
<action type="add">
An issue in JPA server has been corrected where if a CodeSystem
resource was deleted, it was not possible to create a new resource
with the same URI as the previous one
</action>
</release>
<release version="2.5" date="2017-06-08">
<action type="fix">