Fix interaction between terminology cache and validation location (#1700)

* DO NOT MERGE TO MASTER

Contains replication for validation location issue

* Don't let the validator mutate a cached result

* Revert filtering of ValidationTests

* WIP start ValidationResult equality implementation

* Move BaseWorkerContext testing to BaseWorkerContextTests

* A little more cleanup

* Code cleanup, and check that cached ValidationResult is a copy

* Complete ValidationResult equals method.
This commit is contained in:
dotasek 2024-07-29 10:12:55 -04:00 committed by GitHub
parent 68fbee28bc
commit f30150ff4b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 552 additions and 367 deletions

View File

@ -1286,7 +1286,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
}
if (res != null) {
updateUnsupportedCodeSystems(res, code, getCodeKey(code));
return res;
return new ValidationResult(res);
}
List<OperationOutcomeIssueComponent> issues = new ArrayList<>();
@ -1566,7 +1566,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
if (cachingAllowed) {
res = txCache.getValidation(cacheToken);
if (res != null) {
return res;
return new ValidationResult(res);
}
}
for (Coding c : code.getCoding()) {

View File

@ -1,9 +1,6 @@
package org.hl7.fhir.r5.terminologies.utilities;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.*;
import org.hl7.fhir.r5.model.CodeableConcept;
import org.hl7.fhir.r5.model.Coding;
@ -35,6 +32,30 @@ public class ValidationResult {
+ errorClass + ", txLink=" + txLink + "]";
}
public ValidationResult(ValidationResult validationResult) {
this.definition = validationResult.definition == null ? null : validationResult.definition.copy();
this.preferredDisplay = validationResult.preferredDisplay;
this.system = validationResult.system;
this.version = validationResult.version;
this.severity = validationResult.severity;
if (validationResult.messages != null) {
this.messages.addAll(validationResult.messages);
}
this.errorClass = validationResult.errorClass;
this.txLink = validationResult.txLink;
this.diagnostics = validationResult.diagnostics;
if (validationResult.issues != null) {
for (OperationOutcomeIssueComponent issue : validationResult.issues) {
this.issues.add(issue.copy());
}
}
this.codeableConcept = validationResult.codeableConcept == null ? null : validationResult.codeableConcept.copy();
this.unknownSystems = validationResult.unknownSystems == null ? null : new HashSet<>(validationResult.unknownSystems);
this.inactive = validationResult.inactive;
this.status = validationResult.status;
this.server = validationResult.server;
}
public ValidationResult(IssueSeverity severity, String message, List<OperationOutcomeIssueComponent> issues) {
this.severity = severity;
if (message != null) {
@ -334,4 +355,57 @@ public class ValidationResult {
this.server = server;
}
public boolean equals(Object otherObject) {
if (!(otherObject instanceof ValidationResult)) {
return false;
}
ValidationResult other = (ValidationResult) otherObject;
if (!Objects.equals(this.system, other.system)) {
return false;
}
if (!Objects.equals(this.version, other.version)) {
return false;
}
if (!Objects.equals(this.preferredDisplay, other.preferredDisplay)) {
return false;
}
if (!Objects.equals(this.severity, other.severity)) {
return false;
}
if (!Objects.equals(this.definition, other.definition)) {
return false;
}
if (!Objects.equals(this.messages, other.messages)) {
return false;
}
if (!Objects.equals(this.errorClass, other.errorClass)) {
return false;
}
if (!Objects.equals(this.txLink, other.txLink)) {
return false;
}
if (!Objects.equals(this.diagnostics, other.diagnostics)) {
return false;
}
if (!Objects.equals(this.issues, other.issues)) {
return false;
}
if (!Objects.equals(this.codeableConcept, other.codeableConcept)) {
return false;
}
if (!Objects.equals(this.unknownSystems, other.unknownSystems)) {
return false;
}
if (this.inactive != other.inactive) {
return false;
}
if (!Objects.equals(this.status, other.status)) {
return false;
}
if (!Objects.equals(this.server, other.server)) {
return false;
}
return true;
}
}

View File

@ -1,31 +1,224 @@
package org.hl7.fhir.r5.context;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.model.CanonicalResource;
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.ValueSet;
import org.hl7.fhir.r5.model.*;
import org.hl7.fhir.r5.terminologies.client.ITerminologyClient;
import org.hl7.fhir.r5.terminologies.client.TerminologyClientContext;
import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpander;
import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome;
import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache;
import org.hl7.fhir.r5.terminologies.utilities.ValidationResult;
import org.hl7.fhir.r5.terminologies.validation.ValueSetValidator;
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier;
import org.hl7.fhir.utilities.FhirPublication;
import org.hl7.fhir.utilities.ToolingClientLogger;
import org.hl7.fhir.utilities.npm.BasePackageCacheManager;
import org.hl7.fhir.utilities.npm.NpmPackage;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import net.sourceforge.plantuml.tim.stdlib.GetVariableValue;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@ExtendWith(MockitoExtension.class)
public class BaseWorkerContextTests {
private static final String DUMMY_URL = "dummyUrl";
@Spy
BaseWorkerContext context = new BaseWorkerContext(){
@Override
public String getVersion() {
return "4.0.1";
}
@Override
public IResourceValidator newValidator() throws FHIRException {
return null;
}
@Override
public <T extends Resource> T fetchResourceRaw(Class<T> class_, String uri) {
return null;
}
@Override
public void cachePackage(PackageInformation packageInfo) {
}
@Override
public List<String> getResourceNames() {
return List.of();
}
@Override
public int loadFromPackage(NpmPackage pi, IContextResourceLoader loader) throws FileNotFoundException, IOException, FHIRException {
return 0;
}
@Override
public int loadFromPackage(NpmPackage pi, IContextResourceLoader loader, List<String> types) throws FileNotFoundException, IOException, FHIRException {
return 0;
}
@Override
public int loadFromPackageAndDependencies(NpmPackage pi, IContextResourceLoader loader, BasePackageCacheManager pcm) throws FileNotFoundException, IOException, FHIRException {
return 0;
}
@Override
public boolean hasPackage(String id, String ver) {
return false;
}
@Override
public boolean hasPackage(PackageInformation pack) {
return false;
}
@Override
public PackageInformation getPackage(String id, String ver) {
return null;
}
@Override
public String getSpecUrl() {
return "";
}
};
@Mock
TerminologyCache terminologyCache;
@Mock
ToolingClientLogger txLog;
@Mock
ITerminologyClient terminologyClient;
@Mock
TerminologyCache.CacheToken cacheToken;
ValidationResult cachedValidationResult = new ValidationResult(ValidationMessage.IssueSeverity.INFORMATION, "dummyMessageForCached", List.of());
ValidationResult createdValidationResult = new ValidationResult(ValidationMessage.IssueSeverity.INFORMATION, "dummyMessageForCreated", List.of());
@Mock
ValueSetExpansionOutcome expectedExpansionResult;
@Mock
ValueSetValidator valueSetCheckerSimple;
@Mock
ValueSetExpander valueSetExpanderSimple;
@Mock
Parameters pIn;
@Mock
Parameters expParameters;
public static final TerminologyCapabilities terminologyCapabilities = new TerminologyCapabilities();
static { terminologyCapabilities.getExpansion().setParameter(Arrays.asList());}
public static final CapabilityStatement.CapabilityStatementSoftwareComponent software = new CapabilityStatement.CapabilityStatementSoftwareComponent();
static { software.setVersion("dummyVersion"); }
public static final CapabilityStatement capabilitiesStatement = new CapabilityStatement();
static { capabilitiesStatement.setSoftware(software);}
private final static Parameters pInWithDependentResources = new Parameters();
static {
pInWithDependentResources.addParameter("includeDefinition", false);
pInWithDependentResources.addParameter("excludeNester", false);
pInWithDependentResources.addParameter("incomplete-ok", true);
}
public static class ValueSetMatcher implements ArgumentMatcher<ValueSet> {
private ValueSet left;
ValueSetMatcher(ValueSet left) {
this.left = left;
}
@Override
public boolean matches(ValueSet right) {
return left.getStatus().equals(right.getStatus())
&& left.getCompose().equalsDeep(right.getCompose());
}
}
public static class CodingMatcher implements ArgumentMatcher<Coding> {
final private Coding left;
CodingMatcher(Coding left) { this.left = left; }
public boolean matches(Coding right) {
return left.equalsShallow(right);
}
}
public static class ParametersMatcher implements ArgumentMatcher<Parameters> {
final private Parameters left;
ParametersMatcher(Parameters left) {
this.left = left;
}
@Override
public boolean matches(Parameters right) {
return left.equalsShallow(right);
}
}
public static class TerminologyClientContextMatcher implements ArgumentMatcher<TerminologyClientContext> {
final private TerminologyClientContext left;
TerminologyClientContextMatcher(TerminologyClientContext left) {
this.left = left;
}
@Override
public boolean matches(TerminologyClientContext argument) {
return left.getAddress().equals(argument.getAddress());
}
}
@BeforeEach
public void beforeEach() {
Mockito.doReturn(DUMMY_URL).when(terminologyClient).getAddress();
context.initTxCache(terminologyCache);
context.expParameters = expParameters;
context.terminologyClientManager.setMasterClient(terminologyClient, false);
context.txLog = txLog;
}
public BaseWorkerContextTests() throws IOException {
}
private BaseWorkerContext getBaseWorkerContext() throws IOException {
BaseWorkerContext baseWorkerContext = new BaseWorkerContext() {
@Override
@ -123,4 +316,273 @@ public class BaseWorkerContextTests {
baseWorkerContext.addServerValidationParameters(baseWorkerContext.getTxClientManager().getMaster(), new ValueSet(), pin, new ValidationOptions(FhirPublication.fromCode(baseWorkerContext.getVersion())));
assertNull(pin.getParameter("mode"));
}
@Test
public void testValidateCodingWithCache() throws IOException {
ValidationOptions validationOptions = new ValidationOptions(FhirPublication.R5).withGuessSystem().withVersionFlexible(false);
ValueSet valueSet = new ValueSet();
Coding coding = new Coding();
Mockito.doReturn(cacheToken).when(terminologyCache).generateValidationToken(validationOptions, coding, valueSet, expParameters);
Mockito.doReturn(cachedValidationResult).when(terminologyCache).getValidation(cacheToken);
ValidationContextCarrier ctxt = mock(ValidationContextCarrier.class);
ValidationResult actualValidationResult = context.validateCode(validationOptions, coding, valueSet, ctxt);
assertNotSame(cachedValidationResult, actualValidationResult);
assertEquals(cachedValidationResult, actualValidationResult);
Mockito.verify(valueSetCheckerSimple, times(0)).validateCode("Coding", coding);
Mockito.verify(terminologyCache).getValidation(cacheToken);
Mockito.verify(terminologyCache, times(0)).cacheValidation(any(), any(), anyBoolean());
}
@Test
public void testValidateCodingWithValueSetChecker() throws IOException {
ValidationOptions validationOptions = new ValidationOptions(FhirPublication.R5).withGuessSystem().withVersionFlexible(false);
ValueSet valueSet = new ValueSet();
Coding coding = new Coding();
Mockito.doReturn(cacheToken).when(terminologyCache).generateValidationToken(validationOptions, coding, valueSet, expParameters);
Mockito.doReturn(valueSetCheckerSimple).when(context).constructValueSetCheckerSimple(any(), any(), any());
Mockito.doReturn(createdValidationResult).when(valueSetCheckerSimple).validateCode(eq("Coding"), any(Coding.class));
ValidationContextCarrier ctxt = mock(ValidationContextCarrier.class);
ValidationResult actualValidationResult = context.validateCode(validationOptions, coding, valueSet, ctxt);
assertSame(createdValidationResult, actualValidationResult);
Mockito.verify(valueSetCheckerSimple).validateCode(eq("Coding"), argThat(new CodingMatcher(coding)));
Mockito.verify(terminologyCache).getValidation(cacheToken);
Mockito.verify(terminologyCache).cacheValidation(eq(cacheToken), same(createdValidationResult),eq(false));
}
@Test
public void testValidateCodingWithServer() throws IOException {
ValidationOptions validationOptions = new ValidationOptions(FhirPublication.R5).withGuessSystem().withVersionFlexible(false).withNoClient();
ValueSet valueSet = new ValueSet();
Coding coding = new Coding();
Mockito.doReturn(cacheToken).when(terminologyCache).generateValidationToken(validationOptions, coding, valueSet, expParameters);
Mockito.doReturn(pIn).when(context).constructParameters(validationOptions, coding);
TerminologyClientContext terminologyClientContext = context.getTxClientManager().getMaster();
Mockito.doReturn(createdValidationResult).when(context).validateOnServer(terminologyClientContext, valueSet, pIn, validationOptions);
ValidationContextCarrier ctxt = mock(ValidationContextCarrier.class);
ValidationResult actualValidationResult = context.validateCode(validationOptions, coding, valueSet, ctxt);
assertSame(createdValidationResult, actualValidationResult);
Mockito.verify(valueSetCheckerSimple, times(0)).validateCode("Coding", coding);
Mockito.verify(terminologyCache).getValidation(cacheToken);
Mockito.verify(terminologyCache).cacheValidation(eq(cacheToken), same(createdValidationResult),eq(true));
}
@Test
public void testValidateCodableConceptWithCache() throws IOException {
CodeableConcept codeableConcept = new CodeableConcept();
ValueSet valueSet = new ValueSet();
Mockito.doReturn(cacheToken).when(terminologyCache).generateValidationToken(CacheTestUtils.validationOptions, codeableConcept, valueSet, expParameters);
Mockito.doReturn(cachedValidationResult).when(terminologyCache).getValidation(cacheToken);
ValidationResult actualValidationResult = context.validateCode(CacheTestUtils.validationOptions, codeableConcept, valueSet);
assertNotSame(cachedValidationResult, actualValidationResult);
assertEquals(cachedValidationResult, actualValidationResult);
Mockito.verify(valueSetCheckerSimple, times(0)).validateCode("CodeableConcept", codeableConcept);
Mockito.verify(terminologyCache).getValidation(cacheToken);
Mockito.verify(terminologyCache, times(0)).cacheValidation(any(), any(), anyBoolean());
}
@Test
public void testValidateCodableConceptWithValueSetChecker() throws IOException {
Mockito.doReturn(valueSetCheckerSimple).when(context).constructValueSetCheckerSimple(any(), any());
Mockito.doReturn(createdValidationResult).when(valueSetCheckerSimple).validateCode(eq("CodeableConcept"),any(CodeableConcept.class));
CodeableConcept codeableConcept = new CodeableConcept();
ValueSet valueSet = new ValueSet();
Mockito.doReturn(cacheToken).when(terminologyCache).generateValidationToken(CacheTestUtils.validationOptions, codeableConcept, valueSet, expParameters);
ValidationResult validationResultB = context.validateCode(CacheTestUtils.validationOptions, codeableConcept, valueSet);
assertSame(createdValidationResult, validationResultB);
Mockito.verify(valueSetCheckerSimple).validateCode("CodeableConcept", codeableConcept);
Mockito.verify(terminologyCache).cacheValidation(eq(cacheToken), same(createdValidationResult), eq(false));
Mockito.verify(context, times(0)).validateOnServer(any(), any(), any(), any());
}
@Test
public void testValidateCodableConceptWithServer() throws IOException {
CodeableConcept codeableConcept = new CodeableConcept();
ValueSet valueSet = new ValueSet();
ValidationOptions validationOptions = CacheTestUtils.validationOptions.withNoClient();
Mockito.doReturn(pIn).when(context).constructParameters(validationOptions, codeableConcept);
TerminologyClientContext terminologyClientContext = context.getTxClientManager().getMaster();
Mockito.doReturn(createdValidationResult).when(context).validateOnServer(terminologyClientContext, valueSet, pIn, validationOptions);
Mockito.doReturn(cacheToken).when(terminologyCache).generateValidationToken(validationOptions, codeableConcept, valueSet, expParameters);
ValidationResult validationResultB = context.validateCode(validationOptions, codeableConcept, valueSet);
assertSame(createdValidationResult, validationResultB);
Mockito.verify(valueSetCheckerSimple, times(0)).validateCode("CodeableConcept", codeableConcept);
Mockito.verify(terminologyCache).cacheValidation(eq(cacheToken), same(createdValidationResult), eq(true));
Mockito.verify(context).validateOnServer(terminologyClientContext, valueSet, pIn, validationOptions);
}
@Test
public void testExpandValueSetWithCache() throws IOException {
ValueSet.ConceptSetComponent inc = new ValueSet.ConceptSetComponent();
ValueSet vs = new ValueSet();
vs.setStatus(Enumerations.PublicationStatus.ACTIVE);
vs.setCompose(new ValueSet.ValueSetComposeComponent());
vs.getCompose().setInactive(true);
vs.getCompose().getInclude().add(inc);
Mockito.doReturn(cacheToken).when(terminologyCache).generateExpandToken(argThat(new ValueSetMatcher(vs)),eq(true));
Mockito.doReturn(expectedExpansionResult).when(terminologyCache).getExpansion(cacheToken);
ValueSetExpansionOutcome actualExpansionResult = context.expandVS(inc, true, false);
assertSame(expectedExpansionResult, actualExpansionResult);
Mockito.verify(terminologyCache).getExpansion(cacheToken);
Mockito.verify(terminologyCache, times(0)).cacheExpansion(any(), any(), anyBoolean());
Mockito.verify(terminologyClient, times(0)).expandValueset(any(), any());
}
@Test
public void testExpandValueSetWithClient() throws IOException {
ValueSet.ConceptSetComponent inc = new ValueSet.ConceptSetComponent();
ValueSet vs = new ValueSet();
vs.setStatus(Enumerations.PublicationStatus.ACTIVE);
vs.setCompose(new ValueSet.ValueSetComposeComponent());
vs.getCompose().setInactive(true);
vs.getCompose().getInclude().add(inc);
Mockito.doReturn(cacheToken).when(terminologyCache).generateExpandToken(argThat(new ValueSetMatcher(vs)),eq(true));
TerminologyClientContext terminologyClientContext = context.getTxClientManager().getMaster();
Mockito.doReturn(expParameters).when(context).constructParameters(argThat(new TerminologyClientContextMatcher(terminologyClientContext)),argThat(new ValueSetMatcher(vs)), eq(true));
ValueSet expectedValueSet = new ValueSet();
Mockito.doReturn(expectedValueSet).when(terminologyClient).expandValueset(argThat(new ValueSetMatcher(vs)),
argThat(new ParametersMatcher(pInWithDependentResources)));
ValueSetExpansionOutcome actualExpansionResult = context.expandVS(inc, true, false);
assertEquals(expectedValueSet, actualExpansionResult.getValueset());
Mockito.verify(terminologyCache).getExpansion(cacheToken);
Mockito.verify(terminologyCache).cacheExpansion(cacheToken, actualExpansionResult,true);
}
@Test
public void testExpandValueSet4ArgsWithCache() throws IOException {
ValueSet vs = new ValueSet();
vs.setUrl(DUMMY_URL);
Mockito.doReturn(cacheToken).when(terminologyCache).generateExpandToken(vs,true);
Mockito.doReturn(expectedExpansionResult).when(terminologyCache).getExpansion(cacheToken);
Parameters pIn = new Parameters();
ValueSetExpansionOutcome actualExpansionResult = context.expandVS(vs, true, true, true, pIn);
assertEquals(expectedExpansionResult, actualExpansionResult);
Mockito.verify(terminologyCache).getExpansion(cacheToken);
Mockito.verify(terminologyCache, times(0)).cacheExpansion(any(), any(), anyBoolean());
Mockito.verify(terminologyClient, times(0)).expandValueset(any(), any());
}
private static class ValidationOptionsFhirPublicationMatcher implements ArgumentMatcher<ValidationOptions> {
final FhirPublication fhirPublication;
ValidationOptionsFhirPublicationMatcher(FhirPublication fhirPublication) {
this.fhirPublication = fhirPublication;
}
@Override
public boolean matches(ValidationOptions argument) {
return fhirPublication.toCode().equals(argument.getFhirVersion().toCode());
}
}
@Test
public void testExpandValueSet4ArgsWithValueSetExpanderSimple() throws IOException {
ValueSet vs = new ValueSet();
vs.setUrl(DUMMY_URL);
Mockito.doReturn(cacheToken).when(terminologyCache).generateExpandToken(vs,true);
Parameters pIn = new Parameters();
Mockito.doReturn(vs).when(expectedExpansionResult).getValueset();
Mockito.doReturn(expectedExpansionResult).when(valueSetExpanderSimple).expand(eq(vs),
argThat(new ParametersMatcher(pInWithDependentResources)));
Mockito.doReturn(valueSetExpanderSimple).when(context).constructValueSetExpanderSimple(argThat(new ValidationOptionsFhirPublicationMatcher(vs.getFHIRPublicationVersion())));
ValueSetExpansionOutcome actualExpansionResult = context.expandVS(vs, true, true, true, pIn);
assertEquals(expectedExpansionResult, actualExpansionResult);
Mockito.verify(terminologyCache).getExpansion(cacheToken);
Mockito.verify(terminologyCache).cacheExpansion(cacheToken, actualExpansionResult, false);
Mockito.verify(terminologyClient, times(0)).expandValueset(any(), any());
}
@Test
public void testExpandValueSet4ArgsWithClient() throws IOException {
ValueSet vs = new ValueSet();
vs.setUrl(DUMMY_URL);
Mockito.doReturn(cacheToken).when(terminologyCache).generateExpandToken(vs,true);
Parameters pIn = new Parameters();
ValueSet expectedValueSet = new ValueSet();
expectedValueSet.setUrl("dummyUrl2");
Mockito.doReturn(expectedExpansionResult).when(valueSetExpanderSimple).expand(eq(vs),
argThat(new ParametersMatcher(pInWithDependentResources)));
Mockito.doReturn(valueSetExpanderSimple).when(context).constructValueSetExpanderSimple(argThat(new ValidationOptionsFhirPublicationMatcher(vs.getFHIRPublicationVersion())));
Mockito.doReturn(expectedValueSet).when(terminologyClient).expandValueset(eq(vs), argThat(new ParametersMatcher(pInWithDependentResources)));
ValueSetExpansionOutcome actualExpansionResult = context.expandVS(vs, true, true, true, pIn, false);
assertEquals(expectedValueSet, actualExpansionResult.getValueset());
Mockito.verify(terminologyCache).getExpansion(cacheToken);
Mockito.verify(terminologyCache).cacheExpansion(cacheToken, actualExpansionResult, true);
}
}

View File

@ -31,6 +31,7 @@ import org.hl7.fhir.r5.terminologies.validation.ValueSetValidator;
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier;
import org.hl7.fhir.utilities.FhirPublication;
import org.hl7.fhir.utilities.ToolingClientLogger;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
@ -61,27 +62,6 @@ public class SimpleWorkerContextTests {
@Mock
ITerminologyClient terminologyClient;
@Mock
TerminologyCache.CacheToken cacheToken;
@Mock
ValidationResult expectedValidationResult;
@Mock
ValueSetExpansionOutcome expectedExpansionResult;
@Mock
ValueSetValidator valueSetCheckerSimple;
@Mock
ValueSetExpander valueSetExpanderSimple;
@Mock
Parameters pIn;
@Mock
Parameters expParameters;
public static final TerminologyCapabilities terminologyCapabilities = new TerminologyCapabilities();
static { terminologyCapabilities.getExpansion().setParameter(Arrays.asList());}
@ -93,342 +73,11 @@ public class SimpleWorkerContextTests {
@BeforeEach
public void beforeEach() {
Mockito.doReturn(DUMMY_URL).when(terminologyClient).getAddress();
context.initTxCache(terminologyCache);
context.expParameters = expParameters;
context.terminologyClientManager.setMasterClient(terminologyClient, false);
context.txLog = txLog;
}
private final static Parameters pInWithDependentResources = new Parameters();
static {
pInWithDependentResources.addParameter("includeDefinition", false);
pInWithDependentResources.addParameter("excludeNester", false);
pInWithDependentResources.addParameter("incomplete-ok", true);
}
public class ValueSetMatcher implements ArgumentMatcher<ValueSet> {
private ValueSet left;
ValueSetMatcher(ValueSet left) {
this.left = left;
}
@Override
public boolean matches(ValueSet right) {
return left.getStatus().equals(right.getStatus())
&& left.getCompose().equalsDeep(right.getCompose());
}
}
public class CodingMatcher implements ArgumentMatcher<Coding> {
final private Coding left;
CodingMatcher(Coding left) { this.left = left; }
public boolean matches(Coding right) {
return left.equalsShallow(right);
}
}
public class ParametersMatcher implements ArgumentMatcher<Parameters> {
final private Parameters left;
ParametersMatcher(Parameters left) {
this.left = left;
}
@Override
public boolean matches(Parameters right) {
return left.equalsShallow(right);
}
}
public class TerminologyClientContextMatcher implements ArgumentMatcher<TerminologyClientContext> {
final private TerminologyClientContext left;
TerminologyClientContextMatcher(TerminologyClientContext left) {
this.left = left;
}
@Override
public boolean matches(TerminologyClientContext argument) {
return left.getAddress().equals(argument.getAddress());
}
}
@Test
public void testValidateCodingWithCache() throws IOException {
ValidationOptions validationOptions = new ValidationOptions(FhirPublication.R5).withGuessSystem().withVersionFlexible(false);
ValueSet valueSet = new ValueSet();
Coding coding = new Coding();
Mockito.doReturn(cacheToken).when(terminologyCache).generateValidationToken(validationOptions, coding, valueSet, expParameters);
Mockito.doReturn(expectedValidationResult).when(terminologyCache).getValidation(cacheToken);
ValidationContextCarrier ctxt = mock(ValidationContextCarrier.class);
ValidationResult actualValidationResult = context.validateCode(validationOptions, coding, valueSet, ctxt);
assertEquals(expectedValidationResult, actualValidationResult);
Mockito.verify(valueSetCheckerSimple, times(0)).validateCode("Coding", coding);
Mockito.verify(terminologyCache).getValidation(cacheToken);
Mockito.verify(terminologyCache, times(0)).cacheValidation(any(), any(), anyBoolean());
}
@Test
public void testValidateCodingWithValueSetChecker() throws IOException {
ValidationOptions validationOptions = new ValidationOptions(FhirPublication.R5).withGuessSystem().withVersionFlexible(false);
ValueSet valueSet = new ValueSet();
Coding coding = new Coding();
Mockito.doReturn(cacheToken).when(terminologyCache).generateValidationToken(validationOptions, coding, valueSet, expParameters);
Mockito.doReturn(valueSetCheckerSimple).when(context).constructValueSetCheckerSimple(any(), any(), any());
Mockito.doReturn(expectedValidationResult).when(valueSetCheckerSimple).validateCode(eq("Coding"), any(Coding.class));
ValidationContextCarrier ctxt = mock(ValidationContextCarrier.class);
ValidationResult actualValidationResult = context.validateCode(validationOptions, coding, valueSet, ctxt);
assertEquals(expectedValidationResult, actualValidationResult);
Mockito.verify(valueSetCheckerSimple).validateCode(eq("Coding"), argThat(new CodingMatcher(coding)));
Mockito.verify(terminologyCache).getValidation(cacheToken);
Mockito.verify(terminologyCache).cacheValidation(cacheToken, expectedValidationResult,false);
}
@Test
public void testValidateCodingWithServer() throws IOException {
ValidationOptions validationOptions = new ValidationOptions(FhirPublication.R5).withGuessSystem().withVersionFlexible(false).withNoClient();
ValueSet valueSet = new ValueSet();
Coding coding = new Coding();
Mockito.doReturn(cacheToken).when(terminologyCache).generateValidationToken(validationOptions, coding, valueSet, expParameters);
Mockito.doReturn(pIn).when(context).constructParameters(validationOptions, coding);
TerminologyClientContext terminologyClientContext = context.getTxClientManager().getMaster();
Mockito.doReturn(expectedValidationResult).when(context).validateOnServer(terminologyClientContext, valueSet, pIn, validationOptions);
ValidationContextCarrier ctxt = mock(ValidationContextCarrier.class);
ValidationResult actualValidationResult = context.validateCode(validationOptions, coding, valueSet, ctxt);
assertEquals(expectedValidationResult, actualValidationResult);
Mockito.verify(valueSetCheckerSimple, times(0)).validateCode("Coding", coding);
Mockito.verify(terminologyCache).getValidation(cacheToken);
Mockito.verify(terminologyCache).cacheValidation(cacheToken, expectedValidationResult,true);
}
@Test
public void testValidateCodableConceptWithCache() throws IOException {
CodeableConcept codeableConcept = new CodeableConcept();
ValueSet valueSet = new ValueSet();
Mockito.doReturn(cacheToken).when(terminologyCache).generateValidationToken(CacheTestUtils.validationOptions, codeableConcept, valueSet, expParameters);
Mockito.doReturn(expectedValidationResult).when(terminologyCache).getValidation(cacheToken);
ValidationResult actualValidationResult = context.validateCode(CacheTestUtils.validationOptions, codeableConcept, valueSet);
assertEquals(expectedValidationResult, actualValidationResult);
Mockito.verify(valueSetCheckerSimple, times(0)).validateCode("CodeableConcept", codeableConcept);
Mockito.verify(terminologyCache).getValidation(cacheToken);
Mockito.verify(terminologyCache, times(0)).cacheValidation(any(), any(), anyBoolean());
}
@Test
public void testValidateCodableConceptWithValueSetChecker() throws IOException {
Mockito.doReturn(valueSetCheckerSimple).when(context).constructValueSetCheckerSimple(any(), any());
Mockito.doReturn(expectedValidationResult).when(valueSetCheckerSimple).validateCode(eq("CodeableConcept"),any(CodeableConcept.class));
CodeableConcept codeableConcept = new CodeableConcept();
ValueSet valueSet = new ValueSet();
Mockito.doReturn(cacheToken).when(terminologyCache).generateValidationToken(CacheTestUtils.validationOptions, codeableConcept, valueSet, expParameters);
ValidationResult validationResultB = context.validateCode(CacheTestUtils.validationOptions, codeableConcept, valueSet);
assertEquals(expectedValidationResult, validationResultB);
Mockito.verify(valueSetCheckerSimple).validateCode("CodeableConcept", codeableConcept);
Mockito.verify(terminologyCache).cacheValidation(cacheToken, expectedValidationResult, false);
Mockito.verify(context, times(0)).validateOnServer(any(), any(), any(), any());
}
@Test
public void testValidateCodableConceptWithServer() throws IOException {
CodeableConcept codeableConcept = new CodeableConcept();
ValueSet valueSet = new ValueSet();
ValidationOptions validationOptions = CacheTestUtils.validationOptions.withNoClient();
Mockito.doReturn(pIn).when(context).constructParameters(validationOptions, codeableConcept);
TerminologyClientContext terminologyClientContext = context.getTxClientManager().getMaster();
Mockito.doReturn(expectedValidationResult).when(context).validateOnServer(terminologyClientContext, valueSet, pIn, validationOptions);
Mockito.doReturn(cacheToken).when(terminologyCache).generateValidationToken(validationOptions, codeableConcept, valueSet, expParameters);
ValidationResult validationResultB = context.validateCode(validationOptions, codeableConcept, valueSet);
assertEquals(expectedValidationResult, validationResultB);
Mockito.verify(valueSetCheckerSimple, times(0)).validateCode("CodeableConcept", codeableConcept);
Mockito.verify(terminologyCache).cacheValidation(cacheToken, expectedValidationResult, true);
Mockito.verify(context).validateOnServer(terminologyClientContext, valueSet, pIn, validationOptions);
}
@Test
public void testExpandValueSetWithCache() throws IOException {
ValueSet.ConceptSetComponent inc = new ValueSet.ConceptSetComponent();
ValueSet vs = new ValueSet();
vs.setStatus(Enumerations.PublicationStatus.ACTIVE);
vs.setCompose(new ValueSet.ValueSetComposeComponent());
vs.getCompose().setInactive(true);
vs.getCompose().getInclude().add(inc);
Mockito.doReturn(cacheToken).when(terminologyCache).generateExpandToken(argThat(new ValueSetMatcher(vs)),eq(true));
Mockito.doReturn(expectedExpansionResult).when(terminologyCache).getExpansion(cacheToken);
ValueSetExpansionOutcome actualExpansionResult = context.expandVS(inc, true, false);
assertEquals(expectedExpansionResult, actualExpansionResult);
Mockito.verify(terminologyCache).getExpansion(cacheToken);
Mockito.verify(terminologyCache, times(0)).cacheExpansion(any(), any(), anyBoolean());
Mockito.verify(terminologyClient, times(0)).expandValueset(any(), any());
}
@Test
public void testExpandValueSetWithClient() throws IOException {
ValueSet.ConceptSetComponent inc = new ValueSet.ConceptSetComponent();
ValueSet vs = new ValueSet();
vs.setStatus(Enumerations.PublicationStatus.ACTIVE);
vs.setCompose(new ValueSet.ValueSetComposeComponent());
vs.getCompose().setInactive(true);
vs.getCompose().getInclude().add(inc);
Mockito.doReturn(cacheToken).when(terminologyCache).generateExpandToken(argThat(new ValueSetMatcher(vs)),eq(true));
TerminologyClientContext terminologyClientContext = context.getTxClientManager().getMaster();
Mockito.doReturn(expParameters).when(context).constructParameters(argThat(new TerminologyClientContextMatcher(terminologyClientContext)),argThat(new ValueSetMatcher(vs)), eq(true));
ValueSet expectedValueSet = new ValueSet();
Mockito.doReturn(expectedValueSet).when(terminologyClient).expandValueset(argThat(new ValueSetMatcher(vs)),
argThat(new ParametersMatcher(pInWithDependentResources)));
ValueSetExpansionOutcome actualExpansionResult = context.expandVS(inc, true, false);
assertEquals(expectedValueSet, actualExpansionResult.getValueset());
Mockito.verify(terminologyCache).getExpansion(cacheToken);
Mockito.verify(terminologyCache).cacheExpansion(cacheToken, actualExpansionResult,true);
}
@Test
public void testExpandValueSet4ArgsWithCache() throws IOException {
ValueSet vs = new ValueSet();
vs.setUrl(DUMMY_URL);
Mockito.doReturn(cacheToken).when(terminologyCache).generateExpandToken(vs,true);
Mockito.doReturn(expectedExpansionResult).when(terminologyCache).getExpansion(cacheToken);
Parameters pIn = new Parameters();
ValueSetExpansionOutcome actualExpansionResult = context.expandVS(vs, true, true, true, pIn);
assertEquals(expectedExpansionResult, actualExpansionResult);
Mockito.verify(terminologyCache).getExpansion(cacheToken);
Mockito.verify(terminologyCache, times(0)).cacheExpansion(any(), any(), anyBoolean());
Mockito.verify(terminologyClient, times(0)).expandValueset(any(), any());
}
private class ValidationOptionsFhirPublicationMatcher implements ArgumentMatcher<ValidationOptions> {
final FhirPublication fhirPublication;
ValidationOptionsFhirPublicationMatcher(FhirPublication fhirPublication) {
this.fhirPublication = fhirPublication;
}
@Override
public boolean matches(ValidationOptions argument) {
return fhirPublication.toCode().equals(argument.getFhirVersion().toCode());
}
}
@Test
public void testExpandValueSet4ArgsWithValueSetExpanderSimple() throws IOException {
ValueSet vs = new ValueSet();
vs.setUrl(DUMMY_URL);
Mockito.doReturn(cacheToken).when(terminologyCache).generateExpandToken(vs,true);
Parameters pIn = new Parameters();
Mockito.doReturn(vs).when(expectedExpansionResult).getValueset();
Mockito.doReturn(expectedExpansionResult).when(valueSetExpanderSimple).expand(eq(vs),
argThat(new ParametersMatcher(pInWithDependentResources)));
Mockito.doReturn(valueSetExpanderSimple).when(context).constructValueSetExpanderSimple(argThat(new ValidationOptionsFhirPublicationMatcher(vs.getFHIRPublicationVersion())));
ValueSetExpansionOutcome actualExpansionResult = context.expandVS(vs, true, true, true, pIn);
assertEquals(expectedExpansionResult, actualExpansionResult);
Mockito.verify(terminologyCache).getExpansion(cacheToken);
Mockito.verify(terminologyCache).cacheExpansion(cacheToken, actualExpansionResult, false);
Mockito.verify(terminologyClient, times(0)).expandValueset(any(), any());
}
@Test
public void testExpandValueSet4ArgsWithClient() throws IOException {
ValueSet vs = new ValueSet();
vs.setUrl(DUMMY_URL);
Mockito.doReturn(cacheToken).when(terminologyCache).generateExpandToken(vs,true);
Parameters pIn = new Parameters();
ValueSet expectedValueSet = new ValueSet();
expectedValueSet.setUrl("dummyUrl2");
Mockito.doReturn(expectedExpansionResult).when(valueSetExpanderSimple).expand(eq(vs),
argThat(new ParametersMatcher(pInWithDependentResources)));
Mockito.doReturn(valueSetExpanderSimple).when(context).constructValueSetExpanderSimple(argThat(new ValidationOptionsFhirPublicationMatcher(vs.getFHIRPublicationVersion())));
Mockito.doReturn(expectedValueSet).when(terminologyClient).expandValueset(eq(vs), argThat(new ParametersMatcher(pInWithDependentResources)));
ValueSetExpansionOutcome actualExpansionResult = context.expandVS(vs, true, true, true, pIn, false);
assertEquals(expectedValueSet, actualExpansionResult.getValueset());
Mockito.verify(terminologyCache).getExpansion(cacheToken);
Mockito.verify(terminologyCache).cacheExpansion(cacheToken, actualExpansionResult, true);
}
@Test
public void testInitializationWithCache() {
String address = "dummyUrl";