Patient validate operation with remote terminology service enabled returns 400 bad request (#6124)
* Patient $validate operation with Remote Terminology Service enabled returns 400 Bad Request - failing test * Patient $validate operation with Remote Terminology Service enabled returns 400 Bad Request - implementation
This commit is contained in:
parent
7e75ad27bf
commit
c32784ed51
|
@ -7,6 +7,7 @@ org.hl7.fhir.common.hapi.validation.support.CommonCodeSystemsTerminologyService.
|
|||
org.hl7.fhir.common.hapi.validation.support.CommonCodeSystemsTerminologyService.codeNotFoundInValueSet=Code "{0}" is not in valueset: {1}
|
||||
|
||||
org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport.unknownCodeInSystem=Unknown code "{0}#{1}". The Remote Terminology server {2} returned {3}
|
||||
org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport.unknownCodeInValueSet=Unknown code "{0}#{1}" for ValueSet with URL "{2}". The Remote Terminology server {3} returned {4}
|
||||
|
||||
ca.uhn.fhir.jpa.term.TermReadSvcImpl.expansionRefersToUnknownCs=Unknown CodeSystem URI "{0}" referenced from ValueSet
|
||||
ca.uhn.fhir.jpa.term.TermReadSvcImpl.valueSetNotYetExpanded=ValueSet "{0}" has not yet been pre-expanded. Performing in-memory expansion without parameters. Current status: {1} | {2}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
type: fix
|
||||
issue: 6122
|
||||
title: "Previously, executing the '$validate' operation on a resource instance could result in an HTTP 400 Bad Request
|
||||
instead of an HTTP 200 OK response with a list of validation issues. This has been fixed."
|
|
@ -595,11 +595,11 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
|
|||
fail(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(e.getOperationOutcome()));
|
||||
}
|
||||
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
|
||||
assertEquals(8, myCaptureQueriesListener.getSelectQueriesForCurrentThread().size());
|
||||
assertEquals(10, myCaptureQueriesListener.getSelectQueriesForCurrentThread().size());
|
||||
assertEquals(0, myCaptureQueriesListener.getUpdateQueriesForCurrentThread().size());
|
||||
assertEquals(0, myCaptureQueriesListener.getInsertQueriesForCurrentThread().size());
|
||||
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
|
||||
assertEquals(6, myCaptureQueriesListener.getCommitCount());
|
||||
assertEquals(8, myCaptureQueriesListener.getCommitCount());
|
||||
|
||||
// Validate again (should rely only on caches)
|
||||
myCaptureQueriesListener.clear();
|
||||
|
|
|
@ -33,7 +33,6 @@ import org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent;
|
|||
import org.hl7.fhir.r4.model.Property;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.hl7.fhir.r4.model.Type;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -83,6 +82,7 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup
|
|||
String theCode,
|
||||
String theDisplay,
|
||||
String theValueSetUrl) {
|
||||
|
||||
return invokeRemoteValidateCode(theCodeSystem, theCode, theDisplay, theValueSetUrl, null);
|
||||
}
|
||||
|
||||
|
@ -101,12 +101,7 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup
|
|||
// so let's try to get it from the VS if is not present
|
||||
String codeSystem = theCodeSystem;
|
||||
if (isNotBlank(theCode) && isBlank(codeSystem)) {
|
||||
codeSystem = extractCodeSystemForCode((ValueSet) theValueSet, theCode);
|
||||
}
|
||||
|
||||
// Remote terminology services shouldn't be used to validate codes with an implied system
|
||||
if (isBlank(codeSystem)) {
|
||||
return null;
|
||||
codeSystem = ValidationSupportUtils.extractCodeSystemForCode(theValueSet, theCode);
|
||||
}
|
||||
|
||||
String valueSetUrl = DefaultProfileValidationSupport.getConformanceResourceUrl(myCtx, valueSet);
|
||||
|
@ -118,48 +113,6 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup
|
|||
return invokeRemoteValidateCode(codeSystem, theCode, theDisplay, valueSetUrl, valueSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to obtain the codeSystem of the received code from the received ValueSet
|
||||
*/
|
||||
private String extractCodeSystemForCode(ValueSet theValueSet, String theCode) {
|
||||
if (theValueSet.getCompose() == null
|
||||
|| theValueSet.getCompose().getInclude() == null
|
||||
|| theValueSet.getCompose().getInclude().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (theValueSet.getCompose().getInclude().size() == 1) {
|
||||
ValueSet.ConceptSetComponent include =
|
||||
theValueSet.getCompose().getInclude().iterator().next();
|
||||
return getVersionedCodeSystem(include);
|
||||
}
|
||||
|
||||
// when component has more than one include, their codeSystem(s) could be different, so we need to make sure
|
||||
// that we are picking up the system for the include filter to which the code corresponds
|
||||
for (ValueSet.ConceptSetComponent include : theValueSet.getCompose().getInclude()) {
|
||||
if (include.hasSystem()) {
|
||||
for (ValueSet.ConceptReferenceComponent concept : include.getConcept()) {
|
||||
if (concept.hasCodeElement() && concept.getCode().equals(theCode)) {
|
||||
return getVersionedCodeSystem(include);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// at this point codeSystem couldn't be extracted for a multi-include ValueSet. Just on case it was
|
||||
// because the format was not well handled, let's allow to watch the VS by an easy logging change
|
||||
ourLog.trace("CodeSystem couldn't be extracted for code: {} for ValueSet: {}", theCode, theValueSet.getId());
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getVersionedCodeSystem(ValueSet.ConceptSetComponent theComponent) {
|
||||
String codeSystem = theComponent.getSystem();
|
||||
if (!codeSystem.contains("|") && theComponent.hasVersion()) {
|
||||
codeSystem += "|" + theComponent.getVersion();
|
||||
}
|
||||
return codeSystem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseResource fetchCodeSystem(String theSystem) {
|
||||
// callers of this want the whole resource.
|
||||
|
@ -630,11 +583,22 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup
|
|||
resourceType = "CodeSystem";
|
||||
}
|
||||
|
||||
IBaseParameters output = client.operation()
|
||||
.onType(resourceType)
|
||||
.named("validate-code")
|
||||
.withParameters(input)
|
||||
.execute();
|
||||
IBaseParameters output;
|
||||
try {
|
||||
output = client.operation()
|
||||
.onType(resourceType)
|
||||
.named("validate-code")
|
||||
.withParameters(input)
|
||||
.execute();
|
||||
} catch (ResourceNotFoundException | InvalidRequestException ex) {
|
||||
ourLog.error(ex.getMessage(), ex);
|
||||
CodeValidationResult result = new CodeValidationResult();
|
||||
result.setSeverity(IssueSeverity.ERROR);
|
||||
String errorMessage = buildErrorMessage(
|
||||
theCodeSystem, theCode, theValueSetUrl, theValueSet, client.getServerBase(), ex.getMessage());
|
||||
result.setMessage(errorMessage);
|
||||
return result;
|
||||
}
|
||||
|
||||
List<String> resultValues = ParametersUtil.getNamedParameterValuesAsString(getFhirContext(), output, "result");
|
||||
if (resultValues.isEmpty() || isBlank(resultValues.get(0))) {
|
||||
|
@ -666,6 +630,21 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup
|
|||
return retVal;
|
||||
}
|
||||
|
||||
private String buildErrorMessage(
|
||||
String theCodeSystem,
|
||||
String theCode,
|
||||
String theValueSetUrl,
|
||||
IBaseResource theValueSet,
|
||||
String theServerUrl,
|
||||
String theServerMessage) {
|
||||
if (theValueSetUrl == null && theValueSet == null) {
|
||||
return getErrorMessage("unknownCodeInSystem", theCodeSystem, theCode, theServerUrl, theServerMessage);
|
||||
} else {
|
||||
return getErrorMessage(
|
||||
"unknownCodeInValueSet", theCodeSystem, theCode, theValueSetUrl, theServerUrl, theServerMessage);
|
||||
}
|
||||
}
|
||||
|
||||
protected IBaseParameters buildValidateCodeInputParameters(
|
||||
String theCodeSystem, String theCode, String theDisplay, String theValueSetUrl, IBaseResource theValueSet) {
|
||||
IBaseParameters params = ParametersUtil.newInstance(getFhirContext());
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
package org.hl7.fhir.common.hapi.validation.support;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public final class ValidationSupportUtils {
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(ValidationSupportUtils.class);
|
||||
|
||||
private ValidationSupportUtils() {}
|
||||
|
||||
public static String extractCodeSystemForCode(IBaseResource theValueSet, String theCode) {
|
||||
if (theValueSet instanceof org.hl7.fhir.dstu3.model.ValueSet) {
|
||||
return extractCodeSystemForCodeDSTU3((org.hl7.fhir.dstu3.model.ValueSet) theValueSet, theCode);
|
||||
} else if (theValueSet instanceof ValueSet) {
|
||||
return extractCodeSystemForCodeR4((ValueSet) theValueSet, theCode);
|
||||
} else if (theValueSet instanceof org.hl7.fhir.r5.model.ValueSet) {
|
||||
return extractCodeSystemForCodeR5((org.hl7.fhir.r5.model.ValueSet) theValueSet, theCode);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to obtain the codeSystem of the received code from the input DSTU3 ValueSet
|
||||
*/
|
||||
private static String extractCodeSystemForCodeDSTU3(org.hl7.fhir.dstu3.model.ValueSet theValueSet, String theCode) {
|
||||
if (theValueSet.getCompose().getInclude().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (theValueSet.getCompose().getInclude().size() == 1) {
|
||||
org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent include =
|
||||
theValueSet.getCompose().getInclude().iterator().next();
|
||||
return include.hasSystem() ? getVersionedCodeSystem(include.getSystem(), include.getVersion()) : null;
|
||||
}
|
||||
|
||||
// when component has more than one include, their codeSystem(s) could be different, so we need to make sure
|
||||
// that we are picking up the system for the include filter to which the code corresponds
|
||||
for (org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent include :
|
||||
theValueSet.getCompose().getInclude()) {
|
||||
if (include.hasSystem()) {
|
||||
for (org.hl7.fhir.dstu3.model.ValueSet.ConceptReferenceComponent concept : include.getConcept()) {
|
||||
if (concept.hasCodeElement() && concept.getCode().equals(theCode)) {
|
||||
return getVersionedCodeSystem(include.getSystem(), include.getVersion());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// at this point codeSystem couldn't be extracted for a multi-include ValueSet. Just on case it was
|
||||
// because the format was not well handled, let's allow to watch the VS by an easy logging change
|
||||
logCodeAndValueSet(theCode, theValueSet.getId());
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to obtain the codeSystem of the received code from the input R4 ValueSet
|
||||
*/
|
||||
private static String extractCodeSystemForCodeR4(ValueSet theValueSet, String theCode) {
|
||||
if (theValueSet.getCompose().getInclude().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (theValueSet.getCompose().getInclude().size() == 1) {
|
||||
ValueSet.ConceptSetComponent include =
|
||||
theValueSet.getCompose().getInclude().iterator().next();
|
||||
return include.hasSystem() ? getVersionedCodeSystem(include.getSystem(), include.getVersion()) : null;
|
||||
}
|
||||
|
||||
// when component has more than one include, their codeSystem(s) could be different, so we need to make sure
|
||||
// that we are picking up the system for the include filter to which the code corresponds
|
||||
for (ValueSet.ConceptSetComponent include : theValueSet.getCompose().getInclude()) {
|
||||
if (include.hasSystem()) {
|
||||
for (ValueSet.ConceptReferenceComponent concept : include.getConcept()) {
|
||||
if (concept.hasCodeElement() && concept.getCode().equals(theCode)) {
|
||||
return getVersionedCodeSystem(include.getSystem(), include.getVersion());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// at this point codeSystem couldn't be extracted for a multi-include ValueSet. Just on case it was
|
||||
// because the format was not well handled, let's allow to watch the VS by an easy logging change
|
||||
logCodeAndValueSet(theCode, theValueSet.getId());
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getVersionedCodeSystem(String theCodeSystem, String theVersion) {
|
||||
if (!theCodeSystem.contains("|") && theVersion != null) {
|
||||
return theCodeSystem + "|" + theVersion;
|
||||
}
|
||||
return theCodeSystem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to obtain the codeSystem of the received code from the input R5 ValueSet
|
||||
*/
|
||||
private static String extractCodeSystemForCodeR5(org.hl7.fhir.r5.model.ValueSet theValueSet, String theCode) {
|
||||
if (theValueSet.getCompose().getInclude().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (theValueSet.getCompose().getInclude().size() == 1) {
|
||||
org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent include =
|
||||
theValueSet.getCompose().getInclude().iterator().next();
|
||||
return include.hasSystem() ? getVersionedCodeSystem(include.getSystem(), include.getVersion()) : null;
|
||||
}
|
||||
|
||||
// when component has more than one include, their codeSystem(s) could be different, so we need to make sure
|
||||
// that we are picking up the system for the include filter to which the code corresponds
|
||||
for (org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent include :
|
||||
theValueSet.getCompose().getInclude()) {
|
||||
if (include.hasSystem()) {
|
||||
for (org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent concept : include.getConcept()) {
|
||||
if (concept.hasCodeElement() && concept.getCode().equals(theCode)) {
|
||||
return getVersionedCodeSystem(include.getSystem(), include.getVersion());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// at this point codeSystem couldn't be extracted for a multi-include ValueSet. Just on case it was
|
||||
// because the format was not well handled, let's allow to watch the VS by an easy logging change
|
||||
logCodeAndValueSet(theCode, theValueSet.getId());
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void logCodeAndValueSet(String theCode, String theValueSet) {
|
||||
ourLog.trace("CodeSystem couldn't be extracted for code: {} for ValueSet: {}", theCode, theValueSet);
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ import org.apache.commons.lang3.Validate;
|
|||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.fhir.ucum.UcumService;
|
||||
import org.hl7.fhir.common.hapi.validation.support.ValidationSupportUtils;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
@ -25,11 +26,13 @@ import org.hl7.fhir.r5.context.IWorkerContextManager;
|
|||
import org.hl7.fhir.r5.model.CodeSystem;
|
||||
import org.hl7.fhir.r5.model.CodeableConcept;
|
||||
import org.hl7.fhir.r5.model.Coding;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||
import org.hl7.fhir.r5.model.NamingSystem;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome;
|
||||
import org.hl7.fhir.r5.model.PackageInformation;
|
||||
import org.hl7.fhir.r5.model.Parameters;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
import org.hl7.fhir.r5.model.StringType;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.profilemodel.PEBuilder;
|
||||
|
@ -66,7 +69,7 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
|
|||
private final VersionCanonicalizer myVersionCanonicalizer;
|
||||
private final LoadingCache<ResourceKey, IBaseResource> myFetchResourceCache;
|
||||
private volatile List<StructureDefinition> myAllStructures;
|
||||
private org.hl7.fhir.r5.model.Parameters myExpansionProfile;
|
||||
private Parameters myExpansionProfile;
|
||||
|
||||
public VersionSpecificWorkerContextWrapper(
|
||||
ValidationSupportContext theValidationSupportContext, VersionCanonicalizer theVersionCanonicalizer) {
|
||||
|
@ -215,7 +218,7 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
|
|||
}
|
||||
|
||||
@Override
|
||||
public org.hl7.fhir.r5.model.Parameters getExpansionParameters() {
|
||||
public Parameters getExpansionParameters() {
|
||||
return myExpansionProfile;
|
||||
}
|
||||
|
||||
|
@ -224,7 +227,7 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
|
|||
setExpansionProfile(expParameters);
|
||||
}
|
||||
|
||||
public void setExpansionProfile(org.hl7.fhir.r5.model.Parameters expParameters) {
|
||||
public void setExpansionProfile(Parameters expParameters) {
|
||||
myExpansionProfile = expParameters;
|
||||
}
|
||||
|
||||
|
@ -318,7 +321,7 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
|
|||
issue.getDetails().setText(codeValidationIssue.getMessage());
|
||||
issue.addExtension()
|
||||
.setUrl("http://hl7.org/fhir/StructureDefinition/operationoutcome-message-id")
|
||||
.setValue(new org.hl7.fhir.r5.model.StringType("Terminology_PassThrough_TX_Message"));
|
||||
.setValue(new StringType("Terminology_PassThrough_TX_Message"));
|
||||
issues.add(issue);
|
||||
}
|
||||
return issues;
|
||||
|
@ -369,8 +372,7 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
|
|||
}
|
||||
|
||||
@Override
|
||||
public ValueSetExpansionOutcome expandVS(
|
||||
org.hl7.fhir.r5.model.ValueSet source, boolean cacheOk, boolean Hierarchical) {
|
||||
public ValueSetExpansionOutcome expandVS(ValueSet source, boolean cacheOk, boolean Hierarchical) {
|
||||
IBaseResource convertedSource;
|
||||
try {
|
||||
convertedSource = myVersionCanonicalizer.valueSetFromValidatorCanonical(source);
|
||||
|
@ -381,7 +383,7 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
|
|||
.getRootValidationSupport()
|
||||
.expandValueSet(myValidationSupportContext, null, convertedSource);
|
||||
|
||||
org.hl7.fhir.r5.model.ValueSet convertedResult = null;
|
||||
ValueSet convertedResult = null;
|
||||
if (expanded.getValueSet() != null) {
|
||||
try {
|
||||
convertedResult = myVersionCanonicalizer.valueSetToValidatorCanonical(expanded.getValueSet());
|
||||
|
@ -399,7 +401,7 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
|
|||
@Override
|
||||
public ValueSetExpansionOutcome expandVS(
|
||||
Resource src,
|
||||
org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent binding,
|
||||
ElementDefinition.ElementDefinitionBindingComponent binding,
|
||||
boolean cacheOk,
|
||||
boolean Hierarchical) {
|
||||
ValueSet valueSet = fetchResource(ValueSet.class, binding.getValueSet(), src);
|
||||
|
@ -427,14 +429,14 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
|
|||
}
|
||||
|
||||
@Override
|
||||
public org.hl7.fhir.r5.model.CodeSystem fetchCodeSystem(String system) {
|
||||
public CodeSystem fetchCodeSystem(String system) {
|
||||
IBaseResource fetched =
|
||||
myValidationSupportContext.getRootValidationSupport().fetchCodeSystem(system);
|
||||
if (fetched == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return (org.hl7.fhir.r5.model.CodeSystem) myVersionCanonicalizer.codeSystemToValidatorCanonical(fetched);
|
||||
return myVersionCanonicalizer.codeSystemToValidatorCanonical(fetched);
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(Msg.code(665) + e);
|
||||
}
|
||||
|
@ -448,7 +450,7 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
|
|||
return null;
|
||||
}
|
||||
try {
|
||||
return (org.hl7.fhir.r5.model.CodeSystem) myVersionCanonicalizer.codeSystemToValidatorCanonical(fetched);
|
||||
return myVersionCanonicalizer.codeSystemToValidatorCanonical(fetched);
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(Msg.code(1992) + e);
|
||||
}
|
||||
|
@ -746,8 +748,7 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
|
|||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validateCode(
|
||||
ValidationOptions theOptions, String code, org.hl7.fhir.r5.model.ValueSet theValueSet) {
|
||||
public ValidationResult validateCode(ValidationOptions theOptions, String code, ValueSet theValueSet) {
|
||||
IBaseResource convertedVs = null;
|
||||
try {
|
||||
if (theValueSet != null) {
|
||||
|
@ -757,17 +758,16 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
|
|||
throw new InternalErrorException(Msg.code(690) + e);
|
||||
}
|
||||
|
||||
String system = ValidationSupportUtils.extractCodeSystemForCode(theValueSet, code);
|
||||
|
||||
ConceptValidationOptions validationOptions =
|
||||
convertConceptValidationOptions(theOptions).setInferSystem(true);
|
||||
|
||||
return doValidation(convertedVs, validationOptions, null, code, null);
|
||||
return doValidation(convertedVs, validationOptions, system, code, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validateCode(
|
||||
ValidationOptions theOptions,
|
||||
org.hl7.fhir.r5.model.Coding theCoding,
|
||||
org.hl7.fhir.r5.model.ValueSet theValueSet) {
|
||||
public ValidationResult validateCode(ValidationOptions theOptions, Coding theCoding, ValueSet theValueSet) {
|
||||
IBaseResource convertedVs = null;
|
||||
|
||||
try {
|
||||
|
@ -868,10 +868,7 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
|
|||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validateCode(
|
||||
ValidationOptions theOptions,
|
||||
org.hl7.fhir.r5.model.CodeableConcept code,
|
||||
org.hl7.fhir.r5.model.ValueSet theVs) {
|
||||
public ValidationResult validateCode(ValidationOptions theOptions, CodeableConcept code, ValueSet theVs) {
|
||||
|
||||
List<ValidationResult> validationResultsOk = new ArrayList<>();
|
||||
List<OperationOutcome.OperationOutcomeIssueComponent> issues = new ArrayList<>();
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
package org.hl7.fhir.common.hapi.validation.support;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
public class ValidationSupportUtilsTest {
|
||||
|
||||
public static final String SYSTEM_URL = "http://hl7.org/fhir/ValueSet/administrative-gender";
|
||||
public static final String SYSTEM_VERSION = "3.0.2";
|
||||
public static final String SYSTEM_URL_2 = "http://hl7.org/fhir/ValueSet/other-valueset";
|
||||
public static final String SYSTEM_VERSION_2 = "4.0.1";
|
||||
public static final String VALUE_SET_URL = "http://value.set/url";
|
||||
public static final String CODE = "CODE";
|
||||
public static final String NOT_THE_CODE = "not-the-code";
|
||||
|
||||
@Test
|
||||
public void extractCodeSystemForCode_nullValueSet_returnsNull() {
|
||||
String result = ValidationSupportUtils.extractCodeSystemForCode(null, CODE);
|
||||
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
private static Stream<Arguments> extractCodeSystemForCodeDSTU3TestCases() {
|
||||
List<org.hl7.fhir.dstu3.model.ValueSet.ConceptReferenceComponent> conceptWithCode = Lists.newArrayList(
|
||||
new org.hl7.fhir.dstu3.model.ValueSet.ConceptReferenceComponent().setCode(NOT_THE_CODE),
|
||||
new org.hl7.fhir.dstu3.model.ValueSet.ConceptReferenceComponent().setCode(CODE));
|
||||
|
||||
List<org.hl7.fhir.dstu3.model.ValueSet.ConceptReferenceComponent> conceptNoCode = Lists.newArrayList(
|
||||
new org.hl7.fhir.dstu3.model.ValueSet.ConceptReferenceComponent().setCode(NOT_THE_CODE));
|
||||
|
||||
return Stream.of(
|
||||
Arguments.of(Collections.emptyList(), null, "Empty ValueSet includes"),
|
||||
Arguments.of(Lists.newArrayList(new org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent(),
|
||||
new org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent()),
|
||||
null, "ValueSet includes without system"),
|
||||
Arguments.of(Lists.newArrayList(new org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent()),
|
||||
null, "ValueSet include without system"),
|
||||
Arguments.of(Lists.newArrayList(new org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL)),
|
||||
SYSTEM_URL, "ValueSet include with one system and no code"),
|
||||
Arguments.of(Lists.newArrayList(new org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL).setConcept(conceptWithCode)),
|
||||
SYSTEM_URL, "ValueSet include with one system and code"),
|
||||
Arguments.of(Lists.newArrayList(new org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL).setVersion(SYSTEM_VERSION)),
|
||||
SYSTEM_URL + "|" + SYSTEM_VERSION, "ValueSet include with one versioned system and no code"),
|
||||
Arguments.of(Lists.newArrayList(new org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL),
|
||||
new org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL_2)),
|
||||
null, "ValueSet includes with two systems and no code"),
|
||||
Arguments.of(Lists.newArrayList(new org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL).setConcept(conceptWithCode),
|
||||
new org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL_2)),
|
||||
SYSTEM_URL, "ValueSet includes with two systems and correct code"),
|
||||
Arguments.of(Lists.newArrayList(new org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL).setVersion(SYSTEM_VERSION).setConcept(conceptWithCode),
|
||||
new org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL_2).setVersion(SYSTEM_VERSION_2)),
|
||||
SYSTEM_URL + "|" + SYSTEM_VERSION, "ValueSet includes with two systems with versions and correct code"),
|
||||
Arguments.of(Lists.newArrayList(new org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL).setConcept(conceptNoCode),
|
||||
new org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL_2)),
|
||||
null, "ValueSet includes with two systems and different code"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("extractCodeSystemForCodeDSTU3TestCases")
|
||||
public void extractCodeSystemForCodeDSTU3_withDifferentValueSetIncludes_returnsCorrectResult(List<org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent> theValueSetComponents,
|
||||
String theExpectedCodeSystem, String theMessage) {
|
||||
// setup
|
||||
org.hl7.fhir.dstu3.model.ValueSet valueSet = new org.hl7.fhir.dstu3.model.ValueSet();
|
||||
valueSet.setUrl(VALUE_SET_URL);
|
||||
valueSet.setCompose(new org.hl7.fhir.dstu3.model.ValueSet.ValueSetComposeComponent().setInclude(theValueSetComponents));
|
||||
|
||||
// execute
|
||||
String result = ValidationSupportUtils.extractCodeSystemForCode(valueSet, CODE);
|
||||
|
||||
// validate
|
||||
assertEquals(theExpectedCodeSystem, result, theMessage);
|
||||
}
|
||||
|
||||
private static Stream<Arguments> extractCodeSystemForCodeR4TestCases() {
|
||||
List<ValueSet.ConceptReferenceComponent> conceptWithCode = Lists.newArrayList(
|
||||
new ValueSet.ConceptReferenceComponent().setCode(NOT_THE_CODE),
|
||||
new ValueSet.ConceptReferenceComponent().setCode(CODE));
|
||||
|
||||
List<ValueSet.ConceptReferenceComponent> conceptNoCode = Lists.newArrayList(
|
||||
new ValueSet.ConceptReferenceComponent().setCode(NOT_THE_CODE));
|
||||
|
||||
return Stream.of(
|
||||
Arguments.of(Collections.emptyList(), null, "Empty ValueSet includes"),
|
||||
Arguments.of(Lists.newArrayList(new ValueSet.ConceptSetComponent(), new ValueSet.ConceptSetComponent()),
|
||||
null, "ValueSet includes without system"),
|
||||
Arguments.of(Lists.newArrayList(new ValueSet.ConceptSetComponent()),
|
||||
null, "ValueSet include without system"),
|
||||
Arguments.of(Lists.newArrayList(new ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL)),
|
||||
SYSTEM_URL, "ValueSet include with one system and no code"),
|
||||
Arguments.of(Lists.newArrayList(new ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL).setConcept(conceptWithCode)),
|
||||
SYSTEM_URL, "ValueSet include with one system and code"),
|
||||
Arguments.of(Lists.newArrayList(new ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL).setVersion(SYSTEM_VERSION)),
|
||||
SYSTEM_URL + "|" + SYSTEM_VERSION, "ValueSet include with one versioned system and no code"),
|
||||
Arguments.of(Lists.newArrayList(new ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL),
|
||||
new ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL_2)),
|
||||
null, "ValueSet includes with two systems and no code"),
|
||||
Arguments.of(Lists.newArrayList(new ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL).setConcept(conceptWithCode),
|
||||
new ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL_2)),
|
||||
SYSTEM_URL, "ValueSet includes with two systems and correct code"),
|
||||
Arguments.of(Lists.newArrayList(new ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL).setVersion(SYSTEM_VERSION).setConcept(conceptWithCode),
|
||||
new ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL_2).setVersion(SYSTEM_VERSION_2)),
|
||||
SYSTEM_URL + "|" + SYSTEM_VERSION, "ValueSet includes with two systems with versions and correct code"),
|
||||
Arguments.of(Lists.newArrayList(new ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL).setConcept(conceptNoCode),
|
||||
new ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL_2)),
|
||||
null, "ValueSet includes with two systems and different code"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("extractCodeSystemForCodeR4TestCases")
|
||||
public void extractCodeSystemForCodeR4_withDifferentValueSetIncludes_returnsCorrectResult(List<ValueSet.ConceptSetComponent> theValueSetComponents,
|
||||
String theExpectedCodeSystem, String theMessage) {
|
||||
// setup
|
||||
ValueSet valueSet = new ValueSet();
|
||||
valueSet.setUrl(VALUE_SET_URL);
|
||||
valueSet.setCompose(new ValueSet.ValueSetComposeComponent().setInclude(theValueSetComponents));
|
||||
|
||||
// execute
|
||||
String result = ValidationSupportUtils.extractCodeSystemForCode(valueSet, CODE);
|
||||
|
||||
// validate
|
||||
assertEquals(theExpectedCodeSystem, result, theMessage);
|
||||
}
|
||||
|
||||
private static Stream<Arguments> extractCodeSystemForCodeR5TestCases() {
|
||||
List<org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent> conceptWithCode = Lists.newArrayList(
|
||||
new org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent().setCode(NOT_THE_CODE),
|
||||
new org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent().setCode(CODE));
|
||||
|
||||
List<org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent> conceptNoCode = Lists.newArrayList(
|
||||
new org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent().setCode(NOT_THE_CODE));
|
||||
|
||||
return Stream.of(
|
||||
Arguments.of(Collections.emptyList(), null, "Empty ValueSet includes"),
|
||||
Arguments.of(Lists.newArrayList(new org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent(),
|
||||
new org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent()),
|
||||
null, "ValueSet includes without system"),
|
||||
Arguments.of(Lists.newArrayList(new org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent()),
|
||||
null, "ValueSet include without system"),
|
||||
Arguments.of(Lists.newArrayList(new org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL)),
|
||||
SYSTEM_URL, "ValueSet include with one system and no code"),
|
||||
Arguments.of(Lists.newArrayList(new org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL).setConcept(conceptWithCode)),
|
||||
SYSTEM_URL, "ValueSet include with one system and code"),
|
||||
Arguments.of(Lists.newArrayList(new org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL).setVersion(SYSTEM_VERSION)),
|
||||
SYSTEM_URL + "|" + SYSTEM_VERSION, "ValueSet include with one versioned system and no code"),
|
||||
Arguments.of(Lists.newArrayList(new org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL),
|
||||
new org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL_2)),
|
||||
null, "ValueSet includes with two systems and no code"),
|
||||
Arguments.of(Lists.newArrayList(new org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL).setConcept(conceptWithCode),
|
||||
new org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL_2)),
|
||||
SYSTEM_URL, "ValueSet includes with two systems and correct code"),
|
||||
Arguments.of(Lists.newArrayList(new org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL).setVersion(SYSTEM_VERSION).setConcept(conceptWithCode),
|
||||
new org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL_2).setVersion(SYSTEM_VERSION_2)),
|
||||
SYSTEM_URL + "|" + SYSTEM_VERSION, "ValueSet includes with two systems with versions and correct code"),
|
||||
Arguments.of(Lists.newArrayList(new org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL).setConcept(conceptNoCode),
|
||||
new org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent().setSystem(SYSTEM_URL_2)),
|
||||
null, "ValueSet includes with two systems and different code"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("extractCodeSystemForCodeR5TestCases")
|
||||
public void extractCodeSystemForCodeR5_withDifferentValueSetIncludes_returnsCorrectResult(List<org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent> theValueSetComponents,
|
||||
String theExpectedCodeSystem, String theMessage) {
|
||||
// setup
|
||||
org.hl7.fhir.r5.model.ValueSet valueSet = new org.hl7.fhir.r5.model.ValueSet();
|
||||
valueSet.setUrl(VALUE_SET_URL);
|
||||
valueSet.setCompose(new org.hl7.fhir.r5.model.ValueSet.ValueSetComposeComponent().setInclude(theValueSetComponents));
|
||||
|
||||
// execute
|
||||
String result = ValidationSupportUtils.extractCodeSystemForCode(valueSet, CODE);
|
||||
|
||||
// validate
|
||||
assertEquals(theExpectedCodeSystem, result, theMessage);
|
||||
}
|
||||
}
|
|
@ -8,11 +8,17 @@ import ca.uhn.fhir.fhirpath.BaseValidationTestWithInlineMocks;
|
|||
import ca.uhn.fhir.i18n.HapiLocalizer;
|
||||
import ca.uhn.hapi.converters.canonical.VersionCanonicalizer;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.utilities.validation.ValidationOptions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
|
||||
|
@ -68,6 +74,28 @@ public class VersionSpecificWorkerContextWrapperTest extends BaseValidationTestW
|
|||
wrapper.cacheResource(mock(Resource.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateCode_normally_resolvesCodeSystemFromValueSet() {
|
||||
// setup
|
||||
IValidationSupport validationSupport = mockValidationSupport();
|
||||
ValidationSupportContext mockContext = mockValidationSupportContext(validationSupport);
|
||||
VersionCanonicalizer versionCanonicalizer = new VersionCanonicalizer(FhirContext.forR5Cached());
|
||||
VersionSpecificWorkerContextWrapper wrapper = new VersionSpecificWorkerContextWrapper(mockContext, versionCanonicalizer);
|
||||
|
||||
ValueSet valueSet = new ValueSet();
|
||||
valueSet.getCompose().addInclude().setSystem("http://codesystems.com/system").addConcept().setCode("code0");
|
||||
valueSet.getCompose().addInclude().setSystem("http://codesystems.com/system2").addConcept().setCode("code2");
|
||||
when(validationSupport.fetchResource(eq(ValueSet.class), eq("http://somevalueset"))).thenReturn(valueSet);
|
||||
when(validationSupport.validateCodeInValueSet(any(), any(), any(), any(), any(), any())).thenReturn(new IValidationSupport.CodeValidationResult());
|
||||
|
||||
// execute
|
||||
wrapper.validateCode(new ValidationOptions(), "code0", valueSet);
|
||||
|
||||
// verify
|
||||
verify(validationSupport, times(1)).validateCodeInValueSet(any(), any(), eq("http://codesystems.com/system"), eq("code0"), any(), any());
|
||||
verify(validationSupport, times(1)).validateCode(any(), any(), eq("http://codesystems.com/system"), eq("code0"), any(), any());
|
||||
}
|
||||
|
||||
private IValidationSupport mockValidationSupportWithTwoBinaries() {
|
||||
IValidationSupport validationSupport;
|
||||
validationSupport = mockValidationSupport();
|
||||
|
|
|
@ -1266,7 +1266,8 @@ public class FhirInstanceValidatorDstu3Test extends BaseValidationTestWithInline
|
|||
|
||||
ValidationResult output = myVal.validateWithResult(input);
|
||||
logResultsAndReturnAll(output);
|
||||
assertThat(output.getMessages().get(0).getMessage()).contains("The value provided ('notvalidcode') was not found in the value set 'ObservationStatus'");
|
||||
assertThat(output.getMessages().get(0).getMessage()).contains("Unknown code 'http://hl7.org/fhir/observation-status#notvalidcode'");
|
||||
assertThat(output.getMessages().get(1).getMessage()).contains("The value provided ('notvalidcode') was not found in the value set 'ObservationStatus'");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -45,6 +45,7 @@ import org.hl7.fhir.r4.model.CodeType;
|
|||
import org.hl7.fhir.r4.model.Consent;
|
||||
import org.hl7.fhir.r4.model.ContactPoint;
|
||||
import org.hl7.fhir.r4.model.DateTimeType;
|
||||
import org.hl7.fhir.r4.model.Enumerations;
|
||||
import org.hl7.fhir.r4.model.Extension;
|
||||
import org.hl7.fhir.r4.model.IntegerType;
|
||||
import org.hl7.fhir.r4.model.Media;
|
||||
|
@ -107,6 +108,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.nullable;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
|
@ -126,6 +128,7 @@ public class FhirInstanceValidatorR4Test extends BaseValidationTestWithInlineMoc
|
|||
private FhirValidator myFhirValidator;
|
||||
private ArrayList<String> myValidConcepts;
|
||||
private Set<String> myValidSystems = new HashSet<>();
|
||||
private Set<String> myValidValueSets = new HashSet<>();
|
||||
private Map<String, StructureDefinition> myStructureDefinitionMap = new HashMap<>();
|
||||
private CachingValidationSupport myValidationSupport;
|
||||
private IValidationSupport myMockSupport;
|
||||
|
@ -135,6 +138,10 @@ public class FhirInstanceValidatorR4Test extends BaseValidationTestWithInlineMoc
|
|||
myValidConcepts.add(theSystem + "___" + theCode);
|
||||
}
|
||||
|
||||
private void addValidValueSet(String theValueSetUrl) {
|
||||
myValidValueSets.add(theValueSetUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* An invalid local reference should not cause a ServiceException.
|
||||
*/
|
||||
|
@ -266,6 +273,16 @@ public class FhirInstanceValidatorR4Test extends BaseValidationTestWithInlineMoc
|
|||
}
|
||||
});
|
||||
|
||||
when(myMockSupport.isValueSetSupported(any(), nullable(String.class))).thenAnswer(new Answer<Boolean>() {
|
||||
@Override
|
||||
public Boolean answer(InvocationOnMock theInvocation) {
|
||||
String argument = theInvocation.getArgument(1, String.class);
|
||||
boolean retVal = myValidValueSets.contains(argument);
|
||||
ourLog.debug("isValueSetSupported({}) : {}", argument, retVal);
|
||||
return retVal;
|
||||
}
|
||||
});
|
||||
|
||||
when(myMockSupport.validateCode(any(), any(), nullable(String.class), nullable(String.class), nullable(String.class), nullable(String.class))).thenAnswer(new Answer<IValidationSupport.CodeValidationResult>() {
|
||||
@Override
|
||||
public IValidationSupport.CodeValidationResult answer(InvocationOnMock theInvocation) {
|
||||
|
@ -855,6 +872,25 @@ public class FhirInstanceValidatorR4Test extends BaseValidationTestWithInlineMoc
|
|||
assertTrue(output.isSuccessful());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidate_patientWithGenderCode_resolvesCodeSystemFromValueSet() {
|
||||
// setup
|
||||
Patient patient = new Patient();
|
||||
patient.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
|
||||
addValidConcept("http://hl7.org/fhir/administrative-gender", "male");
|
||||
addValidValueSet("http://hl7.org/fhir/ValueSet/administrative-gender");
|
||||
|
||||
// execute
|
||||
ValidationResult output = myFhirValidator.validateWithResult(patient);
|
||||
logResultsAndReturnNonInformationalOnes(output);
|
||||
|
||||
// verify
|
||||
assertTrue(output.isSuccessful());
|
||||
verify(myMockSupport, times(1)).validateCodeInValueSet(any(), any(), eq("http://hl7.org/fhir/administrative-gender"), eq("male"), any(), any());
|
||||
verify(myMockSupport, times(1)).validateCode(any(), any(), eq("http://hl7.org/fhir/administrative-gender"), eq("male"), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateProfileWithExtension() throws IOException, FHIRException {
|
||||
PrePopulatedValidationSupport valSupport = new PrePopulatedValidationSupport(ourCtx);
|
||||
|
@ -1298,7 +1334,8 @@ public class FhirInstanceValidatorR4Test extends BaseValidationTestWithInlineMoc
|
|||
"</Observation>";
|
||||
ValidationResult output = myFhirValidator.validateWithResult(input);
|
||||
logResultsAndReturnAll(output);
|
||||
assertEquals("The value provided ('notvalidcode') was not found in the value set 'ObservationStatus' (http://hl7.org/fhir/ValueSet/observation-status|4.0.1), and a code is required from this value set (error message = Unknown code 'notvalidcode' for in-memory expansion of ValueSet 'http://hl7.org/fhir/ValueSet/observation-status')", output.getMessages().get(0).getMessage());
|
||||
assertThat(output.getMessages().get(0).getMessage()).contains("Unknown code 'http://hl7.org/fhir/observation-status#notvalidcode'");
|
||||
assertThat(output.getMessages().get(1).getMessage()).contains("The value provided ('notvalidcode') was not found in the value set 'ObservationStatus' (http://hl7.org/fhir/ValueSet/observation-status|4.0.1), and a code is required from this value set (error message = Unknown code 'http://hl7.org/fhir/observation-status#notvalidcode' for in-memory expansion of ValueSet 'http://hl7.org/fhir/ValueSet/observation-status')");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1488,10 +1525,18 @@ public class FhirInstanceValidatorR4Test extends BaseValidationTestWithInlineMoc
|
|||
input.getValueQuantity().setCode("Heck");
|
||||
output = myFhirValidator.validateWithResult(input);
|
||||
all = logResultsAndReturnNonInformationalOnes(output);
|
||||
assertThat(all).hasSize(2);
|
||||
assertThat(all).hasSize(3);
|
||||
// validate first error, it has similar message as second error, but location is different
|
||||
// as in R4 (as opposed to R4B/R5) Observation.value.ofType(Quantity) has no ValueSet binding,
|
||||
// there is no `Unknown code for ValueSet` error message
|
||||
assertThat(all.get(0).getMessage()).contains("Error processing unit 'Heck': The unit 'Heck' is unknown' at position 0 (for 'http://unitsofmeasure.org#Heck')");
|
||||
assertThat(all.get(1).getMessage()).contains("The value provided ('Heck') was not found in the value set 'Body Temperature Units'");
|
||||
|
||||
assertThat(all.get(0).getLocationString()).contains("Observation.value.ofType(Quantity)");
|
||||
// validate second error, it has similar message as first error, but location is different
|
||||
assertThat(all.get(1).getMessage()).contains("Error processing unit 'Heck': The unit 'Heck' is unknown' at position 0 (for 'http://unitsofmeasure.org#Heck')");
|
||||
assertThat(all.get(1).getLocationString()).contains("Observation.value.ofType(Quantity).code");
|
||||
// validate third error
|
||||
assertThat(all.get(2).getMessage()).contains("The value provided ('Heck') was not found in the value set 'Body Temperature Units'");
|
||||
assertThat(all.get(2).getLocationString()).contains("Observation.value.ofType(Quantity).code");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1600,9 +1645,10 @@ public class FhirInstanceValidatorR4Test extends BaseValidationTestWithInlineMoc
|
|||
"}";
|
||||
ValidationResult output = myFhirValidator.validateWithResult(input);
|
||||
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
|
||||
assertThat(errors.size()).as(errors.toString()).isEqualTo(2);
|
||||
assertThat(errors.get(1).getMessage()).contains("The value provided ('BLAH') was not found in the value set 'CurrencyCode' (http://hl7.org/fhir/ValueSet/currencies|4.0.1)");
|
||||
assertThat(errors.get(1).getMessage()).contains("error message = Unknown code \"urn:iso:std:iso:4217#BLAH\"");
|
||||
assertThat(errors.size()).as(errors.toString()).isEqualTo(3);
|
||||
assertThat(errors.get(1).getMessage()).contains("Unknown code 'urn:iso:std:iso:4217#BLAH'");
|
||||
assertThat(errors.get(2).getMessage()).contains("The value provided ('BLAH') was not found in the value set 'CurrencyCode' (http://hl7.org/fhir/ValueSet/currencies|4.0.1)");
|
||||
assertThat(errors.get(2).getMessage()).contains("error message = Unknown code \"urn:iso:std:iso:4217#BLAH\"");
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@ import ca.uhn.fhir.rest.client.api.IHttpResponse;
|
|||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.rest.param.UriParam;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
|
||||
import ca.uhn.fhir.util.ParametersUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
|
@ -45,11 +47,15 @@ import org.junit.jupiter.api.BeforeEach;
|
|||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
@ -119,6 +125,52 @@ public class RemoteTerminologyServiceValidationSupportR4Test extends BaseValidat
|
|||
assertNull(outcome);
|
||||
}
|
||||
|
||||
public static Stream<Arguments> getRemoteTerminologyServerResponses() {
|
||||
return Stream.of(
|
||||
Arguments.of(new ResourceNotFoundException("System Not Present"), "404 Not Found: System Not Present",
|
||||
"Unknown code \"null#CODE\". The Remote Terminology server", null, null),
|
||||
Arguments.of(new InvalidRequestException("Invalid Request"), "400 Bad Request: Invalid Request",
|
||||
"Unknown code \"null#CODE\". The Remote Terminology server", null, null),
|
||||
Arguments.of(new ResourceNotFoundException("System Not Present"), "404 Not Found: System Not Present",
|
||||
"Unknown code \"NotFoundSystem#CODE\". The Remote Terminology server", "NotFoundSystem", null),
|
||||
Arguments.of(new InvalidRequestException("Invalid Request"), "400 Bad Request: Invalid Request",
|
||||
"Unknown code \"InvalidSystem#CODE\". The Remote Terminology server", "InvalidSystem", null),
|
||||
Arguments.of(new ResourceNotFoundException("System Not Present"), "404 Not Found: System Not Present",
|
||||
"Unknown code \"null#CODE\" for ValueSet with URL \"NotFoundValueSetUrl\". The Remote Terminology server",
|
||||
null, "NotFoundValueSetUrl"),
|
||||
Arguments.of(new InvalidRequestException("Invalid Request"), "400 Bad Request: Invalid Request",
|
||||
"Unknown code \"null#CODE\" for ValueSet with URL \"InvalidValueSetUrl\". The Remote Terminology server", null, "InvalidValueSetUrl"),
|
||||
Arguments.of(new ResourceNotFoundException("System Not Present"), "404 Not Found: System Not Present",
|
||||
"Unknown code \"NotFoundSystem#CODE\" for ValueSet with URL \"NotFoundValueSetUrl\". The Remote Terminology server",
|
||||
"NotFoundSystem", "NotFoundValueSetUrl"),
|
||||
Arguments.of(new InvalidRequestException("Invalid Request"), "400 Bad Request: Invalid Request",
|
||||
"Unknown code \"InvalidSystem#CODE\" for ValueSet with URL \"InvalidValueSetUrl\". The Remote Terminology server", "InvalidSystem", "InvalidValueSetUrl")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource(value = "getRemoteTerminologyServerResponses")
|
||||
public void testValidateCode_codeSystemAndValueSetUrlAreIncorrect_returnsValidationResultWithError(Exception theException,
|
||||
String theServerMessage,
|
||||
String theValidationMessage,
|
||||
String theCodeSystem,
|
||||
String theValueSetUrl) {
|
||||
myCodeSystemProvider.myNextValidateCodeException = theException;
|
||||
myValueSetProvider.myNextValidateCodeException = theException;
|
||||
IValidationSupport.CodeValidationResult outcome = mySvc.validateCode(null, null, theCodeSystem, CODE, DISPLAY, theValueSetUrl);
|
||||
|
||||
validateValidationErrorResult(outcome, theValidationMessage, theServerMessage);
|
||||
}
|
||||
|
||||
private static void validateValidationErrorResult(IValidationSupport.CodeValidationResult outcome, String... theMessages) {
|
||||
assertNotNull(outcome);
|
||||
assertEquals(IValidationSupport.IssueSeverity.ERROR, outcome.getSeverity());
|
||||
assertNotNull(outcome.getMessage());
|
||||
for (String message : theMessages) {
|
||||
assertTrue(outcome.getMessage().contains(message));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCode_forValueSet_returnsCorrectly() {
|
||||
createNextValueSetReturnParameters(true, DISPLAY, null);
|
||||
|
@ -209,20 +261,6 @@ public class RemoteTerminologyServiceValidationSupportR4Test extends BaseValidat
|
|||
assertNull(myValueSetProvider.myLastValueSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remote terminology services shouldn't be used to validate codes with an implied system
|
||||
*/
|
||||
@Test
|
||||
public void testValidateCodeInValueSet_InferSystem() {
|
||||
createNextValueSetReturnParameters(true, DISPLAY, null);
|
||||
|
||||
ValueSet valueSet = new ValueSet();
|
||||
valueSet.setUrl(VALUE_SET_URL);
|
||||
|
||||
IValidationSupport.CodeValidationResult outcome = mySvc.validateCodeInValueSet(null, new ConceptValidationOptions().setInferSystem(true), null, CODE, DISPLAY, valueSet);
|
||||
assertNull(outcome);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTranslateCode_AllInParams_AllOutParams() {
|
||||
myConceptMapProvider.myNextReturnParams = new Parameters();
|
||||
|
@ -342,32 +380,46 @@ public class RemoteTerminologyServiceValidationSupportR4Test extends BaseValidat
|
|||
IValidationSupport.CodeValidationResult outcome = mySvc.validateCodeInValueSet(null,
|
||||
new ConceptValidationOptions().setInferSystem(true), null, CODE, DISPLAY, valueSet);
|
||||
|
||||
// validate service doesn't do early return (as when no code system is present)
|
||||
// validate service doesn't return error message (as when no code system is present)
|
||||
assertNotNull(outcome);
|
||||
assertNull(outcome.getMessage());
|
||||
assertTrue(outcome.isOk());
|
||||
}
|
||||
|
||||
|
||||
@Nested
|
||||
public class MultiComposeIncludeValueSet {
|
||||
|
||||
@Test
|
||||
public void SystemNotPresentReturnsNull() {
|
||||
public static Stream<Arguments> getRemoteTerminologyServerExceptions() {
|
||||
return Stream.of(
|
||||
Arguments.of(new ResourceNotFoundException("System Not Present"), "404 Not Found: System Not Present"),
|
||||
Arguments.of(new InvalidRequestException("Invalid Request"), "400 Bad Request: Invalid Request")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource(value = "getRemoteTerminologyServerExceptions")
|
||||
public void systemNotPresent_returnsValidationResultWithError(Exception theException, String theServerMessage) {
|
||||
myValueSetProvider.myNextValidateCodeException = theException;
|
||||
createNextValueSetReturnParameters(true, DISPLAY, null);
|
||||
|
||||
ValueSet valueSet = new ValueSet();
|
||||
valueSet.setUrl(VALUE_SET_URL);
|
||||
valueSet.setCompose(new ValueSet.ValueSetComposeComponent().setInclude(
|
||||
Lists.newArrayList(new ValueSet.ConceptSetComponent(), new ValueSet.ConceptSetComponent()) ));
|
||||
Lists.newArrayList(new ValueSet.ConceptSetComponent(), new ValueSet.ConceptSetComponent())));
|
||||
|
||||
IValidationSupport.CodeValidationResult outcome = mySvc.validateCodeInValueSet(null,
|
||||
new ConceptValidationOptions().setInferSystem(true), null, CODE, DISPLAY, valueSet);
|
||||
|
||||
assertNull(outcome);
|
||||
String unknownCodeForValueSetError = "Unknown code \"null#CODE\" for ValueSet with URL \"http://value.set/url\". The Remote Terminology server http://";
|
||||
validateValidationErrorResult(outcome, unknownCodeForValueSetError, theServerMessage);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void SystemPresentCodeNotPresentReturnsNull() {
|
||||
@ParameterizedTest
|
||||
@MethodSource(value = "getRemoteTerminologyServerExceptions")
|
||||
public void systemPresentCodeNotPresent_returnsValidationResultWithError(Exception theException, String theServerMessage) {
|
||||
myValueSetProvider.myNextValidateCodeException = theException;
|
||||
createNextValueSetReturnParameters(true, DISPLAY, null);
|
||||
|
||||
ValueSet valueSet = new ValueSet();
|
||||
|
@ -377,12 +429,13 @@ public class RemoteTerminologyServiceValidationSupportR4Test extends BaseValidat
|
|||
valueSet.setCompose(new ValueSet.ValueSetComposeComponent().setInclude(
|
||||
Lists.newArrayList(
|
||||
new ValueSet.ConceptSetComponent().setSystem(systemUrl),
|
||||
new ValueSet.ConceptSetComponent().setSystem(systemUrl2)) ));
|
||||
new ValueSet.ConceptSetComponent().setSystem(systemUrl2))));
|
||||
|
||||
IValidationSupport.CodeValidationResult outcome = mySvc.validateCodeInValueSet(null,
|
||||
new ConceptValidationOptions().setInferSystem(true), null, CODE, DISPLAY, valueSet);
|
||||
|
||||
assertNull(outcome);
|
||||
String unknownCodeForValueSetError = "Unknown code \"null#CODE\" for ValueSet with URL \"http://value.set/url\". The Remote Terminology server http://";
|
||||
validateValidationErrorResult(outcome, unknownCodeForValueSetError, theServerMessage);
|
||||
}
|
||||
|
||||
|
||||
|
@ -526,6 +579,7 @@ public class RemoteTerminologyServiceValidationSupportR4Test extends BaseValidat
|
|||
|
||||
static private class MyCodeSystemProvider implements IResourceProvider {
|
||||
private SummaryEnum myLastSummaryParam;
|
||||
private Exception myNextValidateCodeException;
|
||||
private UriParam myLastUrlParam;
|
||||
private List<CodeSystem> myNextReturnCodeSystems;
|
||||
private UriType mySystemUrl;
|
||||
|
@ -548,9 +602,12 @@ public class RemoteTerminologyServiceValidationSupportR4Test extends BaseValidat
|
|||
@OperationParam(name = "url", min = 0, max = 1) UriType theSystem,
|
||||
@OperationParam(name = "code", min = 0, max = 1) CodeType theCode,
|
||||
@OperationParam(name = "display", min = 0, max = 1) StringType theDisplay
|
||||
) {
|
||||
) throws Exception {
|
||||
myCode = theCode;
|
||||
mySystemUrl = theSystem;
|
||||
if (myNextValidateCodeException != null) {
|
||||
throw myNextValidateCodeException;
|
||||
}
|
||||
return myNextValidationResult.toParameters(ourCtx);
|
||||
}
|
||||
|
||||
|
@ -566,6 +623,7 @@ public class RemoteTerminologyServiceValidationSupportR4Test extends BaseValidat
|
|||
|
||||
private static class MyValueSetProvider implements IResourceProvider {
|
||||
private Parameters myNextReturnParams;
|
||||
private Exception myNextValidateCodeException;
|
||||
private List<ValueSet> myNextReturnValueSets;
|
||||
private UriType myLastUrl;
|
||||
private CodeType myLastCode;
|
||||
|
@ -589,13 +647,16 @@ public class RemoteTerminologyServiceValidationSupportR4Test extends BaseValidat
|
|||
@OperationParam(name = "system", min = 0, max = 1) UriType theSystem,
|
||||
@OperationParam(name = "display", min = 0, max = 1) StringType theDisplay,
|
||||
@OperationParam(name = "valueSet") ValueSet theValueSet
|
||||
) {
|
||||
) throws Exception {
|
||||
myInvocationCount++;
|
||||
myLastUrl = theValueSetUrl;
|
||||
myLastCode = theCode;
|
||||
myLastSystem = theSystem;
|
||||
myLastDisplay = theDisplay;
|
||||
myLastValueSet = theValueSet;
|
||||
if (myNextValidateCodeException != null) {
|
||||
throw myNextValidateCodeException;
|
||||
}
|
||||
return myNextReturnParams;
|
||||
}
|
||||
|
||||
|
|
|
@ -1216,7 +1216,8 @@ public class FhirInstanceValidatorR4BTest extends BaseValidationTestWithInlineMo
|
|||
"</Observation>";
|
||||
ValidationResult output = myFhirValidator.validateWithResult(input);
|
||||
logResultsAndReturnAll(output);
|
||||
assertEquals("The value provided ('notvalidcode') was not found in the value set 'ObservationStatus' (http://hl7.org/fhir/ValueSet/observation-status|4.3.0), and a code is required from this value set (error message = Unknown code 'notvalidcode' for in-memory expansion of ValueSet 'http://hl7.org/fhir/ValueSet/observation-status')", output.getMessages().get(0).getMessage());
|
||||
assertThat(output.getMessages().get(0).getMessage()).contains("Unknown code 'http://hl7.org/fhir/observation-status#notvalidcode'");
|
||||
assertThat(output.getMessages().get(1).getMessage()).contains("The value provided ('notvalidcode') was not found in the value set 'ObservationStatus' (http://hl7.org/fhir/ValueSet/observation-status|4.3.0), and a code is required from this value set (error message = Unknown code 'http://hl7.org/fhir/observation-status#notvalidcode' for in-memory expansion of ValueSet 'http://hl7.org/fhir/ValueSet/observation-status')");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1366,10 +1367,19 @@ public class FhirInstanceValidatorR4BTest extends BaseValidationTestWithInlineMo
|
|||
input.getValueQuantity().setCode("Heck");
|
||||
output = myFhirValidator.validateWithResult(input);
|
||||
all = logResultsAndReturnNonInformationalOnes(output);
|
||||
assertThat(all).hasSize(2);
|
||||
assertThat(all.get(0).getMessage()).contains("The Coding provided (http://unitsofmeasure.org#Heck) was not found in the value set 'Vital Signs Units' (http://hl7.org/fhir/ValueSet/ucum-vitals-common|4.3.0)");
|
||||
assertThat(all.get(1).getMessage()).contains("The value provided ('Heck') was not found in the value set 'Body Temperature Units'");
|
||||
|
||||
assertThat(all).hasSize(3);
|
||||
// validate first error, in R4B (as opposed to R4) Observation.value.ofType(Quantity) has ValueSet binding,
|
||||
// so first error has `Unknown code for ValueSet` error message
|
||||
assertThat(all.get(0).getMessage()).contains("The Coding provided (http://unitsofmeasure.org#Heck) was not found in the value set 'Vital Signs Units' " +
|
||||
"(http://hl7.org/fhir/ValueSet/ucum-vitals-common|4.3.0), and a code should come from this value set unless it has no suitable code (note that the validator cannot judge what is suitable). " +
|
||||
" (error message = Unknown code 'http://unitsofmeasure.org#Heck' for in-memory expansion of ValueSet 'http://hl7.org/fhir/ValueSet/ucum-vitals-common')");
|
||||
assertThat(all.get(0).getLocationString()).contains("Observation.value.ofType(Quantity)");
|
||||
// validate second error
|
||||
assertThat(all.get(1).getMessage()).contains("Error processing unit 'Heck': The unit 'Heck' is unknown' at position 0 (for 'http://unitsofmeasure.org#Heck')");
|
||||
assertThat(all.get(1).getLocationString()).contains("Observation.value.ofType(Quantity).code");
|
||||
// validate third error
|
||||
assertThat(all.get(2).getMessage()).contains("The value provided ('Heck') was not found in the value set 'Body Temperature Units'");
|
||||
assertThat(all.get(2).getLocationString()).contains("Observation.value.ofType(Quantity).code");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1480,8 +1490,9 @@ public class FhirInstanceValidatorR4BTest extends BaseValidationTestWithInlineMo
|
|||
}""";
|
||||
ValidationResult output = myFhirValidator.validateWithResult(input);
|
||||
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
|
||||
assertThat(errors.size()).as(errors.toString()).isEqualTo(2);
|
||||
assertThat(errors.get(1).getMessage()).contains("The value provided ('BLAH') was not found in the value set 'CurrencyCode' (http://hl7.org/fhir/ValueSet/currencies|4.3.0), and a code is required from this value set");
|
||||
assertThat(errors.size()).as(errors.toString()).isEqualTo(3);
|
||||
assertThat(errors.get(1).getMessage()).contains("Unknown code 'urn:iso:std:iso:4217#BLAH'");
|
||||
assertThat(errors.get(2).getMessage()).contains("The value provided ('BLAH') was not found in the value set 'CurrencyCode' (http://hl7.org/fhir/ValueSet/currencies|4.3.0), and a code is required from this value set");
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -894,7 +894,8 @@ public class FhirInstanceValidatorR5Test extends BaseValidationTestWithInlineMoc
|
|||
"</Observation>";
|
||||
ValidationResult output = myVal.validateWithResult(input);
|
||||
logResultsAndReturnAll(output);
|
||||
assertThat(output.getMessages().get(0).getMessage()).contains("The value provided ('notvalidcode') was not found in the value set 'Observation Status' (http://hl7.org/fhir/ValueSet/observation-status|5.0.0), and a code is required from this value set (error message = Unknown code 'notvalidcode' for in-memory expansion of ValueSet 'http://hl7.org/fhir/ValueSet/observation-status')");
|
||||
assertThat(output.getMessages().get(0).getMessage()).contains("Unknown code 'http://hl7.org/fhir/observation-status#notvalidcode'");
|
||||
assertThat(output.getMessages().get(1).getMessage()).contains("The value provided ('notvalidcode') was not found in the value set 'Observation Status' (http://hl7.org/fhir/ValueSet/observation-status|5.0.0), and a code is required from this value set (error message = Unknown code 'http://hl7.org/fhir/observation-status#notvalidcode' for in-memory expansion of ValueSet 'http://hl7.org/fhir/ValueSet/observation-status')");
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue