From f88298a1fbe100a6e2d5946b7e9d96698f8f3d42 Mon Sep 17 00:00:00 2001 From: James Agnew Date: Tue, 23 Jun 2020 11:35:26 -0400 Subject: [PATCH] Remote terminology service enhancements (#1934) * Remote terminology service enhancements * Add changelog --- .../DefaultProfileValidationSupport.java | 20 +- .../1934-remote-termsvc-enhancements.yaml | 8 + .../validation/validation_support_modules.md | 6 + ...teTerminologyServiceValidationSupport.java | 108 ++++++++-- ...rminologyServiceValidationSupportTest.java | 198 +++++++++++++++--- 5 files changed, 283 insertions(+), 57 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_1_0/1934-remote-termsvc-enhancements.yaml diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/DefaultProfileValidationSupport.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/DefaultProfileValidationSupport.java index bf03f54eb1d..c8e7804fc63 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/DefaultProfileValidationSupport.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/DefaultProfileValidationSupport.java @@ -31,6 +31,7 @@ import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IPrimitiveType; +import javax.annotation.Nullable; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -327,13 +328,7 @@ public class DefaultProfileValidationSupport implements IValidationSupport { } private String getConformanceResourceUrl(IBaseResource theResource) { - String urlValueString = null; - Optional urlValue = getFhirContext().getResourceDefinition(theResource).getChildByName("url").getAccessor().getFirstValueOrNull(theResource); - if (urlValue.isPresent()) { - IPrimitiveType urlValueType = (IPrimitiveType) urlValue.get(); - urlValueString = urlValueType.getValueAsString(); - } - return urlValueString; + return getConformanceResourceUrl(getFhirContext(), theResource); } private List parseBundle(InputStreamReader theReader) { @@ -346,6 +341,17 @@ public class DefaultProfileValidationSupport implements IValidationSupport { } } + @Nullable + public static String getConformanceResourceUrl(FhirContext theFhirContext, IBaseResource theResource) { + String urlValueString = null; + Optional urlValue = theFhirContext.getResourceDefinition(theResource).getChildByName("url").getAccessor().getFirstValueOrNull(theResource); + if (urlValue.isPresent()) { + IPrimitiveType urlValueType = (IPrimitiveType) urlValue.get(); + urlValueString = urlValueType.getValueAsString(); + } + return urlValueString; + } + static List toList(Map theMap) { ArrayList retVal = new ArrayList<>(theMap.values()); return (List) Collections.unmodifiableList(retVal); diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_1_0/1934-remote-termsvc-enhancements.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_1_0/1934-remote-termsvc-enhancements.yaml new file mode 100644 index 00000000000..8a7a29ccd5b --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_1_0/1934-remote-termsvc-enhancements.yaml @@ -0,0 +1,8 @@ +--- +type: add +issue: 1934 +title: "The **RemoteTerminologyServiceValidationSupport** validation support module, which is used to connect to + external/remote terminology services, has been significantly enhanced to provide testing for supported + CodeSystems and ValueSets. It will also now validate codes in fields that are not bound to a specific + ValueSet." + diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/validation_support_modules.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/validation_support_modules.md index afffbe8a490..cdd07b8bd39 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/validation_support_modules.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/validation_support_modules.md @@ -118,6 +118,12 @@ The following table lists vocabulary that is validated by this module: This module validates codes using a remote FHIR-based terminology server. +This module will invoke the following operations on the remote terminology server: + +* **GET [base]/CodeSystem?url=[url]** – Tests whether a given CodeSystem is supported on the server +* **GET [base]/ValueSet?url=[url]** – Tests whether a given ValueSet is supported on the server +* **POST [base]/CodeSystem/$validate-code** – Validate codes in fields where no specific ValueSet is bound +* **POST [base]/ValueSet/$validate-code** – Validate codes in fields where a specific ValueSet is bound # Recipes diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/RemoteTerminologyServiceValidationSupport.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/RemoteTerminologyServiceValidationSupport.java index 619512b1953..5d62a28d619 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/RemoteTerminologyServiceValidationSupport.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/RemoteTerminologyServiceValidationSupport.java @@ -2,13 +2,17 @@ package org.hl7.fhir.common.hapi.validation.support; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.support.ConceptValidationOptions; +import ca.uhn.fhir.context.support.DefaultProfileValidationSupport; import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.context.support.ValidationSupportContext; import ca.uhn.fhir.rest.client.api.IGenericClient; +import ca.uhn.fhir.util.BundleUtil; import ca.uhn.fhir.util.ParametersUtil; import org.apache.commons.lang3.Validate; +import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseParameters; import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r4.model.CodeSystem; import javax.annotation.Nonnull; import java.util.ArrayList; @@ -42,6 +46,64 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup return invokeRemoteValidateCode(theCodeSystem, theCode, theDisplay, theValueSetUrl, null); } + @Override + public CodeValidationResult validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) { + IBaseResource valueSet = theValueSet; + String valueSetUrl = DefaultProfileValidationSupport.getConformanceResourceUrl(myCtx, valueSet); + if (isNotBlank(valueSetUrl)) { + valueSet = null; + } else { + valueSetUrl = null; + } + return invokeRemoteValidateCode(theCodeSystem, theCode, theDisplay, valueSetUrl, valueSet); + } + + @Override + public IBaseResource fetchCodeSystem(String theSystem) { + IGenericClient client = provideClient(); + Class bundleType = myCtx.getResourceDefinition("Bundle").getImplementingClass(IBaseBundle.class); + IBaseBundle results = client + .search() + .forResource("CodeSystem") + .where(CodeSystem.URL.matches().value(theSystem)) + .returnBundle(bundleType) + .execute(); + List resultsList = BundleUtil.toListOfResources(myCtx, results); + if (resultsList.size() > 0) { + return resultsList.get(0); + } + + return null; + } + + @Override + public IBaseResource fetchValueSet(String theValueSetUrl) { + IGenericClient client = provideClient(); + Class bundleType = myCtx.getResourceDefinition("Bundle").getImplementingClass(IBaseBundle.class); + IBaseBundle results = client + .search() + .forResource("ValueSet") + .where(CodeSystem.URL.matches().value(theValueSetUrl)) + .returnBundle(bundleType) + .execute(); + List resultsList = BundleUtil.toListOfResources(myCtx, results); + if (resultsList.size() > 0) { + return resultsList.get(0); + } + + return null; + } + + @Override + public boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String theSystem) { + return fetchCodeSystem(theSystem) != null; + } + + @Override + public boolean isValueSetSupported(ValidationSupportContext theValidationSupportContext, String theValueSetUrl) { + return fetchValueSet(theValueSetUrl) != null; + } + private IGenericClient provideClient() { IGenericClient retVal = myCtx.newRestfulGenericClient(myBaseUrl); for (Object next : myClientInterceptors) { @@ -50,11 +112,6 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup return retVal; } - @Override - public CodeValidationResult validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) { - return invokeRemoteValidateCode(theCodeSystem, theCode, theDisplay, null, theValueSet); - } - protected CodeValidationResult invokeRemoteValidateCode(String theCodeSystem, String theCode, String theDisplay, String theValueSetUrl, IBaseResource theValueSet) { if (isBlank(theCode)) { return null; @@ -64,23 +121,38 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup IBaseParameters input = ParametersUtil.newInstance(getFhirContext()); - if (isNotBlank(theValueSetUrl)) { - ParametersUtil.addParameterToParametersUri(getFhirContext(), input, "url", theValueSetUrl); - } - ParametersUtil.addParameterToParametersString(getFhirContext(), input, "code", theCode); - if (isNotBlank(theCodeSystem)) { - ParametersUtil.addParameterToParametersUri(getFhirContext(), input, "system", theCodeSystem); - } - if (isNotBlank(theDisplay)) { - ParametersUtil.addParameterToParametersString(getFhirContext(), input, "display", theDisplay); - } - if (theValueSet != null) { - ParametersUtil.addParameterToParameters(getFhirContext(), input, "valueSet", theValueSet); + String resourceType = "ValueSet"; + if (theValueSet == null && theValueSetUrl == null) { + resourceType = "CodeSystem"; + + ParametersUtil.addParameterToParametersUri(getFhirContext(), input, "url", theCodeSystem); + ParametersUtil.addParameterToParametersString(getFhirContext(), input, "code", theCode); + if (isNotBlank(theDisplay)) { + ParametersUtil.addParameterToParametersString(getFhirContext(), input, "display", theDisplay); + } + + } else { + + if (isNotBlank(theValueSetUrl)) { + ParametersUtil.addParameterToParametersUri(getFhirContext(), input, "url", theValueSetUrl); + } + ParametersUtil.addParameterToParametersString(getFhirContext(), input, "code", theCode); + if (isNotBlank(theCodeSystem)) { + ParametersUtil.addParameterToParametersUri(getFhirContext(), input, "system", theCodeSystem); + } + if (isNotBlank(theDisplay)) { + ParametersUtil.addParameterToParametersString(getFhirContext(), input, "display", theDisplay); + } + if (theValueSet != null) { + ParametersUtil.addParameterToParameters(getFhirContext(), input, "valueSet", theValueSet); + } + } + IBaseParameters output = client .operation() - .onType("ValueSet") + .onType(resourceType) .named("validate-code") .withParameters(input) .execute(); diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/support/RemoteTerminologyServiceValidationSupportTest.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/support/RemoteTerminologyServiceValidationSupportTest.java index dda79bab7b4..6d14bb0a3da 100644 --- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/support/RemoteTerminologyServiceValidationSupportTest.java +++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/support/RemoteTerminologyServiceValidationSupportTest.java @@ -5,9 +5,15 @@ import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.Operation; import ca.uhn.fhir.rest.annotation.OperationParam; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.Search; 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.test.utilities.server.RestfulServerRule; +import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.r4.model.BooleanType; +import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.CodeType; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Parameters; @@ -21,6 +27,9 @@ import org.junit.Test; import javax.servlet.http.HttpServletRequest; +import java.util.ArrayList; +import java.util.List; + import static org.hamcrest.Matchers.lessThan; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; @@ -37,13 +46,18 @@ public class RemoteTerminologyServiceValidationSupportTest { @Rule public RestfulServerRule myRestfulServerRule = new RestfulServerRule(ourCtx); - private MyMockTerminologyServiceProvider myProvider; + private MyValueSetProvider myValueSetProvider; private RemoteTerminologyServiceValidationSupport mySvc; + private MyCodeSystemProvider myCodeSystemProvider; @Before public void before() { - myProvider = new MyMockTerminologyServiceProvider(); - myRestfulServerRule.getRestfulServer().registerProvider(myProvider); + myValueSetProvider = new MyValueSetProvider(); + myRestfulServerRule.getRestfulServer().registerProvider(myValueSetProvider); + + myCodeSystemProvider = new MyCodeSystemProvider(); + myRestfulServerRule.getRestfulServer().registerProvider(myCodeSystemProvider); + String baseUrl = "http://localhost:" + myRestfulServerRule.getPort(); mySvc = new RemoteTerminologyServiceValidationSupport(ourCtx); @@ -53,7 +67,7 @@ public class RemoteTerminologyServiceValidationSupportTest { @After public void after() { - assertThat(myProvider.myInvocationCount, lessThan(2)); + assertThat(myValueSetProvider.myInvocationCount, lessThan(2)); } @Test @@ -64,7 +78,7 @@ public class RemoteTerminologyServiceValidationSupportTest { @Test public void testValidateCode_SystemCodeDisplayUrl_Success() { - createNextReturnParameters(true, DISPLAY, null); + createNextValueSetReturnParameters(true, DISPLAY, null); IValidationSupport.CodeValidationResult outcome = mySvc.validateCode(null, null, CODE_SYSTEM, CODE, DISPLAY, VALUE_SET_URL); assertEquals(CODE, outcome.getCode()); @@ -72,16 +86,16 @@ public class RemoteTerminologyServiceValidationSupportTest { assertEquals(null, outcome.getSeverity()); assertEquals(null, outcome.getMessage()); - assertEquals(CODE, myProvider.myLastCode.getCode()); - assertEquals(DISPLAY, myProvider.myLastDisplay.getValue()); - assertEquals(CODE_SYSTEM, myProvider.myLastSystem.getValue()); - assertEquals(VALUE_SET_URL, myProvider.myLastUrl.getValue()); - assertEquals(null, myProvider.myLastValueSet); + assertEquals(CODE, myValueSetProvider.myLastCode.getCode()); + assertEquals(DISPLAY, myValueSetProvider.myLastDisplay.getValue()); + assertEquals(CODE_SYSTEM, myValueSetProvider.myLastSystem.getValue()); + assertEquals(VALUE_SET_URL, myValueSetProvider.myLastUrl.getValue()); + assertEquals(null, myValueSetProvider.myLastValueSet); } @Test public void testValidateCode_SystemCodeDisplayUrl_Error() { - createNextReturnParameters(false, null, ERROR_MESSAGE); + createNextValueSetReturnParameters(false, null, ERROR_MESSAGE); IValidationSupport.CodeValidationResult outcome = mySvc.validateCode(null, null, CODE_SYSTEM, CODE, DISPLAY, VALUE_SET_URL); assertEquals(null, outcome.getCode()); @@ -89,16 +103,32 @@ public class RemoteTerminologyServiceValidationSupportTest { assertEquals(IValidationSupport.IssueSeverity.ERROR, outcome.getSeverity()); assertEquals(ERROR_MESSAGE, outcome.getMessage()); - assertEquals(CODE, myProvider.myLastCode.getCode()); - assertEquals(DISPLAY, myProvider.myLastDisplay.getValue()); - assertEquals(CODE_SYSTEM, myProvider.myLastSystem.getValue()); - assertEquals(VALUE_SET_URL, myProvider.myLastUrl.getValue()); - assertEquals(null, myProvider.myLastValueSet); + assertEquals(CODE, myValueSetProvider.myLastCode.getCode()); + assertEquals(DISPLAY, myValueSetProvider.myLastDisplay.getValue()); + assertEquals(CODE_SYSTEM, myValueSetProvider.myLastSystem.getValue()); + assertEquals(VALUE_SET_URL, myValueSetProvider.myLastUrl.getValue()); + assertEquals(null, myValueSetProvider.myLastValueSet); } + @Test + public void testValidateCodeInCodeSystem_Good() { + createNextCodeSystemReturnParameters(true, DISPLAY, null); + + IValidationSupport.CodeValidationResult outcome = mySvc.validateCode(null, null, CODE_SYSTEM, CODE, DISPLAY, null); + assertEquals(CODE, outcome.getCode()); + assertEquals(DISPLAY, outcome.getDisplay()); + assertEquals(null, outcome.getSeverity()); + assertEquals(null, outcome.getMessage()); + + assertEquals(CODE, myCodeSystemProvider.myLastCode.getCode()); + assertEquals(DISPLAY, myCodeSystemProvider.myLastDisplay.getValue()); + assertEquals(CODE_SYSTEM, myCodeSystemProvider.myLastUrl.getValueAsString()); + } + + @Test public void testValidateCodeInValueSet_SystemCodeDisplayVS_Good() { - createNextReturnParameters(true, DISPLAY, null); + createNextValueSetReturnParameters(true, DISPLAY, null); ValueSet valueSet = new ValueSet(); valueSet.setUrl(VALUE_SET_URL); @@ -109,34 +139,127 @@ public class RemoteTerminologyServiceValidationSupportTest { assertEquals(null, outcome.getSeverity()); assertEquals(null, outcome.getMessage()); - assertEquals(CODE, myProvider.myLastCode.getCode()); - assertEquals(DISPLAY, myProvider.myLastDisplay.getValue()); - assertEquals(CODE_SYSTEM, myProvider.myLastSystem.getValue()); - assertEquals(null, myProvider.myLastUrl); - assertEquals(VALUE_SET_URL, myProvider.myLastValueSet.getUrl()); + assertEquals(CODE, myValueSetProvider.myLastCode.getCode()); + assertEquals(DISPLAY, myValueSetProvider.myLastDisplay.getValue()); + assertEquals(CODE_SYSTEM, myValueSetProvider.myLastSystem.getValue()); + assertEquals(VALUE_SET_URL, myValueSetProvider.myLastUrl.getValueAsString()); + assertEquals(null, myValueSetProvider.myLastValueSet); } - public void createNextReturnParameters(boolean theResult, String theDisplay, String theMessage) { - myProvider.myNextReturn = new Parameters(); - myProvider.myNextReturn.addParameter("result", theResult); - myProvider.myNextReturn.addParameter("display", theDisplay); + @Test + public void testIsValueSetSupported_False() { + myValueSetProvider.myNextReturnValueSets = new ArrayList<>(); + + boolean outcome = mySvc.isValueSetSupported(null, "http://loinc.org/VS"); + assertEquals(false, outcome); + assertEquals("http://loinc.org/VS", myValueSetProvider.myLastUrlParam.getValue()); + } + + @Test + public void testIsValueSetSupported_True() { + myValueSetProvider.myNextReturnValueSets = new ArrayList<>(); + myValueSetProvider.myNextReturnValueSets.add((ValueSet) new ValueSet().setId("ValueSet/123")); + + boolean outcome = mySvc.isValueSetSupported(null, "http://loinc.org/VS"); + assertEquals(true, outcome); + assertEquals("http://loinc.org/VS", myValueSetProvider.myLastUrlParam.getValue()); + } + + @Test + public void testIsCodeSystemSupported_False() { + myCodeSystemProvider.myNextReturnCodeSystems = new ArrayList<>(); + + boolean outcome = mySvc.isCodeSystemSupported(null, "http://loinc.org"); + assertEquals(false, outcome); + assertEquals("http://loinc.org", myCodeSystemProvider.myLastUrlParam.getValue()); + } + + @Test + public void testIsCodeSystemSupported_True() { + myCodeSystemProvider.myNextReturnCodeSystems = new ArrayList<>(); + myCodeSystemProvider.myNextReturnCodeSystems.add((CodeSystem) new CodeSystem().setId("CodeSystem/123")); + + boolean outcome = mySvc.isCodeSystemSupported(null, "http://loinc.org"); + assertEquals(true, outcome); + assertEquals("http://loinc.org", myCodeSystemProvider.myLastUrlParam.getValue()); + } + + private void createNextCodeSystemReturnParameters(boolean theResult, String theDisplay, String theMessage) { + myCodeSystemProvider.myNextReturnParams = new Parameters(); + myCodeSystemProvider.myNextReturnParams.addParameter("result", theResult); + myCodeSystemProvider.myNextReturnParams.addParameter("display", theDisplay); if (theMessage != null) { - myProvider.myNextReturn.addParameter("message", theMessage); + myCodeSystemProvider.myNextReturnParams.addParameter("message", theMessage); } } - private static class MyMockTerminologyServiceProvider { + private void createNextValueSetReturnParameters(boolean theResult, String theDisplay, String theMessage) { + myValueSetProvider.myNextReturnParams = new Parameters(); + myValueSetProvider.myNextReturnParams.addParameter("result", theResult); + myValueSetProvider.myNextReturnParams.addParameter("display", theDisplay); + if (theMessage != null) { + myValueSetProvider.myNextReturnParams.addParameter("message", theMessage); + } + } + + private static class MyCodeSystemProvider implements IResourceProvider { + + private UriParam myLastUrlParam; + private List myNextReturnCodeSystems; + private int myInvocationCount; + private UriType myLastUrl; + private CodeType myLastCode; + private StringType myLastDisplay; + private Parameters myNextReturnParams; + + @Operation(name = "validate-code", idempotent = true, returnParameters = { + @OperationParam(name = "result", type = BooleanType.class, min = 1), + @OperationParam(name = "message", type = StringType.class), + @OperationParam(name = "display", type = StringType.class) + }) + public Parameters validateCode( + HttpServletRequest theServletRequest, + @IdParam(optional = true) IdType theId, + @OperationParam(name = "url", min = 0, max = 1) UriType theCodeSystemUrl, + @OperationParam(name = "code", min = 0, max = 1) CodeType theCode, + @OperationParam(name = "display", min = 0, max = 1) StringType theDisplay + ) { + myInvocationCount++; + myLastUrl = theCodeSystemUrl; + myLastCode = theCode; + myLastDisplay = theDisplay; + return myNextReturnParams; + + } + + @Search + public List find(@RequiredParam(name="url") UriParam theUrlParam) { + myLastUrlParam = theUrlParam; + assert myNextReturnCodeSystems != null; + return myNextReturnCodeSystems; + } + + @Override + public Class getResourceType() { + return CodeSystem.class; + } + } - private Parameters myNextReturn; + private static class MyValueSetProvider implements IResourceProvider { + + + private Parameters myNextReturnParams; + private List myNextReturnValueSets; private UriType myLastUrl; private CodeType myLastCode; private int myInvocationCount; private UriType myLastSystem; private StringType myLastDisplay; private ValueSet myLastValueSet; + private UriParam myLastUrlParam; - @Operation(name = "validate-code", idempotent = true, typeName = "ValueSet", returnParameters = { + @Operation(name = "validate-code", idempotent = true, returnParameters = { @OperationParam(name = "result", type = BooleanType.class, min = 1), @OperationParam(name = "message", type = StringType.class), @OperationParam(name = "display", type = StringType.class) @@ -156,11 +279,22 @@ public class RemoteTerminologyServiceValidationSupportTest { myLastSystem = theSystem; myLastDisplay = theDisplay; myLastValueSet = theValueSet; - return myNextReturn; - + return myNextReturnParams; } + @Search + public List find(@RequiredParam(name="url") UriParam theUrlParam) { + myLastUrlParam = theUrlParam; + assert myNextReturnValueSets != null; + return myNextReturnValueSets; + } + + @Override + public Class getResourceType() { + return ValueSet.class; + } } + }