Add a test

This commit is contained in:
James Agnew 2019-10-30 15:51:46 -04:00
parent b13de41e9f
commit e96500d54f
8 changed files with 323 additions and 53 deletions

View File

@ -28,47 +28,9 @@ import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
public class RuntimeChildPrimitiveDatatypeDefinition extends BaseRuntimeChildDatatypeDefinition {
// private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RuntimeChildPrimitiveDatatypeDefinition.class);
// private IMutator myReferenceMutator;
public RuntimeChildPrimitiveDatatypeDefinition(Field theField, String theElementName, Description theDescriptionAnnotation, Child theChildAnnotation, Class<? extends IBase> theDatatype) {
super(theField, theElementName, theChildAnnotation, theDescriptionAnnotation, theDatatype);
}
// @Override
// void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
// super.sealAndInitialize(theContext, theClassToElementDefinitions);
//
// if (theContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU2_HL7ORG)) {
// if (IReference.class.isAssignableFrom(getDatatype())) {
// String fieldName = getField().getName() + "Target";
// try {
// Field targetField = getField().getDeclaringClass().getField(fieldName);
// if (List.class.isAssignableFrom(targetField.getType())) {
// myReferenceMutator = new FieldListMutator();
// } else if (IBaseResource.class.isAssignableFrom(targetField.getType())) {
// myReferenceMutator = new FieldPlainMutator();
// }
// } catch (Exception e) {
// ourLog.debug("Unable to find target field named {}", fieldName);
// }
// }
// } else {
// if (BaseResourceReferenceDt.class.isAssignableFrom(getDatatype())) {
// myReferenceMutator = new IMutator() {
// @Override
// public void addValue(Object theTarget, IBase theValue) {
// BaseResourceReferenceDt dt = (BaseResourceReferenceDt)theTarget;
// dt.setResource((IBaseResource) theValue);
// }};
// }
// }
//
// }
//
// public IMutator getReferenceMutator() {
// return myReferenceMutator;
// }
}

View File

@ -2,7 +2,6 @@ package ca.uhn.fhir.jpa.config.r5;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.ParserOptions;
import ca.uhn.fhir.jpa.config.BaseConfig;
import ca.uhn.fhir.jpa.config.BaseConfigDstu3Plus;
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
@ -20,7 +19,6 @@ import ca.uhn.fhir.jpa.term.api.ITermVersionAdapterSvc;
import ca.uhn.fhir.jpa.util.ResourceCountCache;
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainR5;
import ca.uhn.fhir.validation.IInstanceValidatorModule;
import ca.uhn.fhir.validation.IValidatorModule;
import org.apache.commons.lang3.time.DateUtils;
import org.hl7.fhir.r5.hapi.ctx.DefaultProfileValidationSupport;
import org.hl7.fhir.r5.hapi.ctx.IValidationSupport;
@ -139,7 +137,7 @@ public class BaseR5Config extends BaseConfigDstu3Plus {
@Bean(autowire = Autowire.BY_TYPE)
public SearchParamExtractorR5 searchParamExtractor() {
return new SearchParamExtractorR5();
return new SearchParamExtractorR5(ctx, new DefaultProfileValidationSupport(), searchParamRegistry);
}
@Bean

View File

@ -34,6 +34,7 @@ import org.hl7.fhir.instance.model.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import javax.measure.quantity.Quantity;
import javax.measure.unit.NonSI;
@ -110,7 +111,6 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
BaseSearchParamExtractor(FhirContext theCtx, ISearchParamRegistry theSearchParamRegistry) {
myContext = theCtx;
mySearchParamRegistry = theSearchParamRegistry;
start();
}
@Override
@ -536,7 +536,6 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
for (IBase nextValue : values) {
addToken_CodeableConcept(theResourceType, theParams, theSearchParam, nextValue);
}
}
private void addDate_Period(String theResourceType, Set<ResourceIndexedSearchParamDate> theParams, RuntimeSearchParam theSearchParam, IBase theValue) {
@ -859,12 +858,14 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
myAddressCountryValueChild = addressDefinition.getChildByName("country");
myAddressPostalCodeValueChild = addressDefinition.getChildByName("postalCode");
BaseRuntimeElementCompositeDefinition<?> capabilityStatementDefinition = getContext().getResourceDefinition("CapabilityStatement");
BaseRuntimeChildDefinition capabilityStatementRestChild = capabilityStatementDefinition.getChildByName("rest");
BaseRuntimeElementCompositeDefinition<?> capabilityStatementRestDefinition = (BaseRuntimeElementCompositeDefinition<?>) capabilityStatementRestChild.getChildByName("rest");
BaseRuntimeChildDefinition capabilityStatementRestSecurityValueChild = capabilityStatementRestDefinition.getChildByName("security");
BaseRuntimeElementCompositeDefinition<?> capabilityStatementRestSecurityDefinition = (BaseRuntimeElementCompositeDefinition<?>) capabilityStatementRestSecurityValueChild.getChildByName("security");
myCapabilityStatementRestSecurityServiceValueChild = capabilityStatementRestSecurityDefinition.getChildByName("service");
if (getContext().getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.DSTU3)) {
BaseRuntimeElementCompositeDefinition<?> capabilityStatementDefinition = getContext().getResourceDefinition("CapabilityStatement");
BaseRuntimeChildDefinition capabilityStatementRestChild = capabilityStatementDefinition.getChildByName("rest");
BaseRuntimeElementCompositeDefinition<?> capabilityStatementRestDefinition = (BaseRuntimeElementCompositeDefinition<?>) capabilityStatementRestChild.getChildByName("rest");
BaseRuntimeChildDefinition capabilityStatementRestSecurityValueChild = capabilityStatementRestDefinition.getChildByName("security");
BaseRuntimeElementCompositeDefinition<?> capabilityStatementRestSecurityDefinition = (BaseRuntimeElementCompositeDefinition<?>) capabilityStatementRestSecurityValueChild.getChildByName("security");
myCapabilityStatementRestSecurityServiceValueChild = capabilityStatementRestSecurityDefinition.getChildByName("service");
}
BaseRuntimeElementCompositeDefinition<?> periodDefinition = (BaseRuntimeElementCompositeDefinition<?>) getContext().getElementDefinition("Period");
myPeriodStartValueChild = periodDefinition.getChildByName("start");

View File

@ -20,6 +20,8 @@ package ca.uhn.fhir.jpa.searchparam.extractor;
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
import ca.uhn.fhir.model.dstu2.composite.ContactPointDt;
import ca.uhn.fhir.util.FhirTerser;
import org.hl7.fhir.instance.model.api.IBase;
@ -32,6 +34,16 @@ import java.util.List;
public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implements ISearchParamExtractor {
public SearchParamExtractorDstu2() {
}
/**
* Constructor for unit tests
*/
SearchParamExtractorDstu2(FhirContext theCtx, ISearchParamRegistry theSearchParamRegistry) {
super(theCtx, theSearchParamRegistry);
start();
}
@Override
protected IValueExtractor getPathValueExtractor(IBaseResource theResource, String theSinglePath) {

View File

@ -61,6 +61,7 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
super(theCtx, theSearchParamRegistry);
myValidationSupport = theValidationSupport;
start(null);
start();
}
@Override

View File

@ -57,6 +57,7 @@ public class SearchParamExtractorR4 extends BaseSearchParamExtractor implements
super(theCtx, theSearchParamRegistry);
myValidationSupport = theValidationSupport;
initFhirPath();
start();
}
@Override

View File

@ -20,10 +20,13 @@ package ca.uhn.fhir.jpa.searchparam.extractor;
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.PathEngineException;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.hapi.ctx.DefaultProfileValidationSupport;
import org.hl7.fhir.r5.hapi.ctx.HapiWorkerContext;
import org.hl7.fhir.r5.hapi.ctx.IValidationSupport;
import org.hl7.fhir.r5.model.*;
@ -44,13 +47,19 @@ public class SearchParamExtractorR5 extends BaseSearchParamExtractor implements
private IValidationSupport myValidationSupport;
private FHIRPathEngine myFhirPathEngine;
/**
* Constructor
*/
public SearchParamExtractorR5() {
super();
}
/**
* Constructor for unit tests
*/
public SearchParamExtractorR5(FhirContext theCtx, DefaultProfileValidationSupport theDefaultProfileValidationSupport, ISearchParamRegistry theSearchParamRegistry) {
super(theCtx, theSearchParamRegistry);
myValidationSupport = theDefaultProfileValidationSupport;
start();
}
@Override
@PostConstruct
public void start() {

View File

@ -0,0 +1,286 @@
package ca.uhn.fhir.jpa.searchparam.extractor;
import ca.uhn.fhir.context.*;
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
import org.hl7.fhir.dstu3.hapi.ctx.DefaultProfileValidationSupport;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseEnumeration;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.Assert.assertEquals;
public class SearchParamExtractorMegaTest {
private static final Logger ourLog = LoggerFactory.getLogger(SearchParamExtractorMegaTest.class);
/**
* This test is my magnum opus :P
*
* It navigates almost every possible path in every FHIR resource in every version of FHIR,
* and creates a resource with that path populated, just to ensure that we can index it
* without generating any warnings.
*/
@Test
public void testAllCombinations() throws Exception {
FhirContext ctx = FhirContext.forDstu2();
ISearchParamRegistry searchParamRegistry = new MySearchParamRegistry(ctx);
process(ctx, new SearchParamExtractorDstu2(ctx, searchParamRegistry));
ctx = FhirContext.forDstu3();
searchParamRegistry = new MySearchParamRegistry(ctx);
process(ctx, new SearchParamExtractorDstu3(null, ctx, new DefaultProfileValidationSupport(), searchParamRegistry));
ctx = FhirContext.forR4();
searchParamRegistry = new MySearchParamRegistry(ctx);
process(ctx, new SearchParamExtractorR4(null, ctx, new org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport(), searchParamRegistry));
ctx = FhirContext.forR5();
searchParamRegistry = new MySearchParamRegistry(ctx);
process(ctx, new SearchParamExtractorR5(ctx, new org.hl7.fhir.r5.hapi.ctx.DefaultProfileValidationSupport(), searchParamRegistry));
}
private void process(FhirContext theCtx, BaseSearchParamExtractor theExtractor) throws Exception {
AtomicInteger indexesCounter = new AtomicInteger();
for (String nextResourceName : theCtx.getResourceNames()) {
RuntimeResourceDefinition resourceDefinition = theCtx.getResourceDefinition(nextResourceName);
List<BaseRuntimeElementDefinition> elementStack = new ArrayList<>();
List<BaseRuntimeChildDefinition> childStack = new ArrayList<>();
processElement(theCtx, theExtractor, resourceDefinition, elementStack, childStack, indexesCounter);
}
ourLog.info("Found {} indexes", indexesCounter.get());
}
private void processElement(FhirContext theCtx, BaseSearchParamExtractor theExtractor, BaseRuntimeElementDefinition theElementDef, List<BaseRuntimeElementDefinition> theElementStack, List<BaseRuntimeChildDefinition> theChildStack, AtomicInteger theIndexesCounter) throws Exception {
if (theElementDef.getName().equals("ElementDefinition")) {
return;
}
theElementStack.add(theElementDef);
if (theElementDef instanceof BaseRuntimeElementCompositeDefinition) {
BaseRuntimeElementCompositeDefinition<?> composite = (BaseRuntimeElementCompositeDefinition) theElementDef;
for (BaseRuntimeChildDefinition nextChild : composite.getChildren()) {
if (theChildStack.contains(nextChild)) {
continue;
}
theChildStack.add(nextChild);
if (nextChild instanceof RuntimeChildResourceBlockDefinition) {
BaseRuntimeElementDefinition<?> def = nextChild.getChildByName(nextChild.getElementName());
processElement(theCtx, theExtractor, def, theElementStack, theChildStack, theIndexesCounter);
} else if (nextChild instanceof BaseRuntimeChildDatatypeDefinition) {
BaseRuntimeElementDefinition<?> def = nextChild.getChildByName(nextChild.getElementName());
processElement(theCtx, theExtractor, def, theElementStack, theChildStack, theIndexesCounter);
} else if (nextChild instanceof RuntimeChildExtension) {
// ignore extensions
} else if (nextChild instanceof RuntimeChildContainedResources) {
// ignore extensions
} else if (nextChild instanceof RuntimeChildResourceDefinition) {
// ignore extensions
} else if (nextChild instanceof RuntimeChildChoiceDefinition) {
RuntimeChildChoiceDefinition choice = (RuntimeChildChoiceDefinition) nextChild;
for (String nextOption : choice.getValidChildNames()) {
BaseRuntimeElementDefinition<?> def = nextChild.getChildByName(nextOption);
processElement(theCtx, theExtractor, def, theElementStack, theChildStack, theIndexesCounter);
}
} else if (nextChild instanceof RuntimeChildDirectResource) {
// ignore
} else {
throw new Exception("Unexpected child type: " + nextChild.getClass());
}
theChildStack.remove(theChildStack.size() - 1);
}
} else if (theElementDef instanceof RuntimePrimitiveDatatypeDefinition) {
handlePathToPrimitive(theCtx, theExtractor, theElementStack, theChildStack, theIndexesCounter);
} else if (theElementDef instanceof RuntimePrimitiveDatatypeNarrativeDefinition) {
// ignore
} else if (theElementDef instanceof RuntimePrimitiveDatatypeXhtmlHl7OrgDefinition) {
// ignore
} else {
throw new Exception("Unexpected def type: " + theElementDef.getClass());
}
theElementStack.remove(theElementStack.size() - 1);
}
private void handlePathToPrimitive(FhirContext theCtx, BaseSearchParamExtractor theExtractor, List<BaseRuntimeElementDefinition> theElementStack, List<BaseRuntimeChildDefinition> theChildStack, AtomicInteger theIndexesCounter) {
IBase previousObject = null;
IBaseResource resource = null;
StringBuilder path = new StringBuilder(theElementStack.get(0).getName());
Object previousChildArguments = null;
for (int i = 0; i < theElementStack.size(); i++) {
BaseRuntimeElementDefinition nextElement = theElementStack.get(i);
if (i > 0) {
previousChildArguments = theChildStack.get(i-1).getInstanceConstructorArguments();
}
IBase nextObject = nextElement.newInstance(previousChildArguments);
if (i == 0) {
resource = (IBaseResource) nextObject;
} else {
BaseRuntimeChildDefinition child = theChildStack.get(i - 1);
child.getMutator().addValue(previousObject, nextObject);
path.append(".").append(child.getChildNameByDatatype(nextObject.getClass()));
}
previousObject = nextObject;
}
IPrimitiveType<?> leaf = (IPrimitiveType<?>) previousObject;
if (leaf instanceof IBaseEnumeration<?>) {
return;
}
String typeName = theCtx.getElementDefinition(leaf.getClass()).getRootParentDefinition().getName();
switch (typeName) {
case "boolean":
leaf.setValueAsString("true");
break;
case "date":
leaf.setValueAsString("2019-10-10");
break;
case "dateTime":
case "instant":
leaf.setValueAsString("2019-10-10T11:11:11Z");
break;
case "integer":
case "decimal":
leaf.setValueAsString("1");
break;
default:
leaf.setValueAsString("a");
break;
}
ourLog.info("Found path: {}", path);
ISearchParamExtractor.SearchParamSet<?> set;
set = theExtractor.extractSearchParamCoords(resource);
assertEquals(0, set.getWarnings().size());
theIndexesCounter.addAndGet(set.size());
set = theExtractor.extractSearchParamDates(resource);
assertEquals(0, set.getWarnings().size());
theIndexesCounter.addAndGet(set.size());
set = theExtractor.extractSearchParamNumber(resource);
assertEquals(0, set.getWarnings().size());
theIndexesCounter.addAndGet(set.size());
set = theExtractor.extractSearchParamStrings(resource);
assertEquals(0, set.getWarnings().size());
theIndexesCounter.addAndGet(set.size());
set = theExtractor.extractSearchParamQuantity(resource);
assertEquals(0, set.getWarnings().size());
theIndexesCounter.addAndGet(set.size());
set = theExtractor.extractSearchParamTokens(resource);
assertEquals(0, set.getWarnings().size());
theIndexesCounter.addAndGet(set.size());
set = theExtractor.extractSearchParamUri(resource);
assertEquals(0, set.getWarnings().size());
theIndexesCounter.addAndGet(set.size());
}
private static class MySearchParamRegistry implements ISearchParamRegistry {
private final FhirContext myCtx;
private List<RuntimeSearchParam> myAddedSearchParams = new ArrayList<>();
private MySearchParamRegistry(FhirContext theCtx) {
myCtx = theCtx;
}
public void addSearchParam(RuntimeSearchParam... theSearchParam) {
myAddedSearchParams.clear();
for (RuntimeSearchParam next : theSearchParam) {
myAddedSearchParams.add(next);
}
}
@Override
public void forceRefresh() {
// nothing
}
@Override
public RuntimeSearchParam getActiveSearchParam(String theResourceName, String theParamName) {
throw new UnsupportedOperationException();
}
@Override
public boolean refreshCacheIfNecessary() {
// nothing
return false;
}
@Override
public Map<String, Map<String, RuntimeSearchParam>> getActiveSearchParams() {
throw new UnsupportedOperationException();
}
@Override
public Map<String, RuntimeSearchParam> getActiveSearchParams(String theResourceName) {
RuntimeResourceDefinition nextResDef = myCtx.getResourceDefinition(theResourceName);
Map<String, RuntimeSearchParam> sps = new HashMap<>();
for (RuntimeSearchParam nextSp : nextResDef.getSearchParams()) {
sps.put(nextSp.getName(), nextSp);
}
for (RuntimeSearchParam next : myAddedSearchParams) {
sps.put(next.getName(), next);
}
return sps;
}
@Override
public List<JpaRuntimeSearchParam> getActiveUniqueSearchParams(String theResourceName, Set<String> theParamNames) {
throw new UnsupportedOperationException();
}
@Override
public List<JpaRuntimeSearchParam> getActiveUniqueSearchParams(String theResourceName) {
throw new UnsupportedOperationException();
}
@Override
public void requestRefresh() {
// nothing
}
@Override
public RuntimeSearchParam getSearchParamByName(RuntimeResourceDefinition theResourceDef, String theParamName) {
return null;
}
@Override
public Collection<RuntimeSearchParam> getSearchParamsByResourceType(RuntimeResourceDefinition theResourceDef) {
return null;
}
}
}