Improve TX scoping for validation (#1925)

* Improve TX scoping for validation

* Test fix

* Test fix

* Some cleanup

* Test fixes

* Test fix
This commit is contained in:
James Agnew 2020-06-17 14:04:12 -04:00 committed by GitHub
parent 0d4e12fe58
commit b6540064ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 253 additions and 36 deletions

View File

@ -6,9 +6,9 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<artifactId>hapi-deployable-pom</artifactId>
<version>5.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
<artifactId>hapi-fhir-elasticsearch-6</artifactId>

View File

@ -150,6 +150,12 @@
<artifactId>hapi-fhir-elasticsearch-6</artifactId>
<version>${project.version}</version>
<classifier>shaded6</classifier>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>

View File

@ -1395,6 +1395,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
}
@Override
@Transactional(propagation = Propagation.SUPPORTS)
public MethodOutcome validate(T theResource, IIdType theId, String theRawResource, EncodingEnum theEncoding, ValidationModeEnum theMode, String theProfile, RequestDetails theRequest) {
if (theRequest != null) {
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequest, theResource, null, theId);

View File

@ -412,8 +412,4 @@ public class TermConcept implements Serializable {
return getChildren().stream().map(t -> t.getChild()).collect(Collectors.toList());
}
public VersionIndependentConcept toVersionIndependentConcept() {
return new VersionIndependentConcept(myCodeSystem.getCodeSystem().getCodeSystemUri(), myCode);
}
}

View File

@ -408,7 +408,7 @@ public class JpaPackageCache extends BasePackageCacheManager implements IHapiPac
.build()
.execute(new HttpGet(thePackageUrl))) {
if (request.getStatusLine().getStatusCode() != 200) {
throw new IOException("Received HTTP " + request.getStatusLine().getStatusCode());
throw new ResourceNotFoundException("Received HTTP " + request.getStatusLine().getStatusCode() + " from URL: " + thePackageUrl);
}
return IOUtils.toByteArray(request.getEntity().getContent());
} catch (IOException e) {

View File

@ -89,6 +89,7 @@ import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Stopwatch;
import net.bytebuddy.implementation.bytecode.Throw;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.time.DateUtils;
@ -177,6 +178,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
private static final TermCodeSystemVersion NO_CURRENT_VERSION = new TermCodeSystemVersion().setId(-1L);
private static boolean ourLastResultsFromTranslationCache; // For testing.
private static boolean ourLastResultsFromTranslationWithReverseCache; // For testing.
private static Runnable myInvokeOnNextCallForUnitTest;
private final int myFetchSize = DEFAULT_FETCH_SIZE;
private final Cache<String, TermCodeSystemVersion> myCodeSystemCurrentVersionCache = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).build();
@Autowired
@ -1299,7 +1301,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
@Nullable
private TermCodeSystemVersion getCurrentCodeSystemVersion(String theUri) {
TermCodeSystemVersion retVal = myCodeSystemCurrentVersionCache.get(theUri, uri -> {
TermCodeSystemVersion retVal = myCodeSystemCurrentVersionCache.get(theUri, uri -> myTxTemplate.execute(tx -> {
TermCodeSystemVersion csv = null;
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(uri);
if (cs != null && cs.getCurrentVersion() != null) {
@ -1310,7 +1312,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
} else {
return NO_CURRENT_VERSION;
}
});
}));
if (retVal == NO_CURRENT_VERSION) {
return null;
}
@ -1935,8 +1937,15 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
}
@Override
@Transactional
public CodeValidationResult validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) {
if (myInvokeOnNextCallForUnitTest != null) {
Runnable invokeOnNextCallForUnitTest = myInvokeOnNextCallForUnitTest;
myInvokeOnNextCallForUnitTest = null;
invokeOnNextCallForUnitTest.run();
}
IPrimitiveType<?> urlPrimitive = myContext.newTerser().getSingleValueOrNull(theValueSet, "url", IPrimitiveType.class);
String url = urlPrimitive.getValueAsString();
if (isNotBlank(url)) {
@ -2106,6 +2115,11 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc {
}
}
@VisibleForTesting
public static void setInvokeOnNextCallForUnitTest(Runnable theInvokeOnNextCallForUnitTest) {
myInvokeOnNextCallForUnitTest = theInvokeOnNextCallForUnitTest;
}
static List<TermConcept> toPersistedConcepts(List<CodeSystem.ConceptDefinitionComponent> theConcept, TermCodeSystemVersion theCodeSystemVersion) {
ArrayList<TermConcept> retVal = new ArrayList<>();

View File

@ -447,16 +447,19 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc {
doDelete(descriptor, loader, counter, myConceptDao);
}
Optional<TermCodeSystem> codeSystemOpt = myCodeSystemDao.findWithCodeSystemVersionAsCurrentVersion(theCodeSystemVersionPid);
if (codeSystemOpt.isPresent()) {
TermCodeSystem codeSystem = codeSystemOpt.get();
ourLog.info(" * Removing code system version {} as current version of code system {}", theCodeSystemVersionPid, codeSystem.getPid());
codeSystem.setCurrentVersion(null);
myCodeSystemDao.save(codeSystem);
}
TransactionTemplate txTemplate = new TransactionTemplate(myTransactionManager);
txTemplate.executeWithoutResult(tx -> {
Optional<TermCodeSystem> codeSystemOpt = myCodeSystemDao.findWithCodeSystemVersionAsCurrentVersion(theCodeSystemVersionPid);
if (codeSystemOpt.isPresent()) {
TermCodeSystem codeSystem = codeSystemOpt.get();
ourLog.info(" * Removing code system version {} as current version of code system {}", theCodeSystemVersionPid, codeSystem.getPid());
codeSystem.setCurrentVersion(null);
myCodeSystemDao.save(codeSystem);
}
ourLog.info(" * Deleting code system version");
myCodeSystemVersionDao.deleteById(theCodeSystemVersionPid);
ourLog.info(" * Deleting code system version");
myCodeSystemVersionDao.deleteById(theCodeSystemVersionPid);
});
}

View File

@ -144,7 +144,7 @@ public class TermReadSvcDstu3 extends BaseTermReadSvcImpl implements IValidation
if (!haveValidated) {
TransactionTemplate txTemplate = new TransactionTemplate(myTransactionManager);
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
codeOpt = txTemplate.execute(t -> findCode(theCodeSystem, theCode).map(c -> c.toVersionIndependentConcept()));
codeOpt = txTemplate.execute(t -> findCode(theCodeSystem, theCode).map(c -> new VersionIndependentConcept(theCodeSystem, c.getCode())));
}
if (codeOpt != null && codeOpt.isPresent()) {

View File

@ -112,7 +112,7 @@ public class TermReadSvcR4 extends BaseTermReadSvcImpl implements ITermReadSvcR4
if (!haveValidated) {
TransactionTemplate txTemplate = new TransactionTemplate(myTransactionManager);
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
codeOpt = txTemplate.execute(t -> findCode(theCodeSystem, theCode).map(c -> c.toVersionIndependentConcept()));
codeOpt = txTemplate.execute(t -> findCode(theCodeSystem, theCode).map(c -> new VersionIndependentConcept(theCodeSystem, c.getCode())));
}
if (codeOpt != null && codeOpt.isPresent()) {

View File

@ -99,7 +99,7 @@ public class TermReadSvcR5 extends BaseTermReadSvcImpl implements IValidationSup
if (!haveValidated) {
TransactionTemplate txTemplate = new TransactionTemplate(myTransactionManager);
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
codeOpt = txTemplate.execute(t -> findCode(theCodeSystem, theCode).map(c -> c.toVersionIndependentConcept()));
codeOpt = txTemplate.execute(t -> findCode(theCodeSystem, theCode).map(c -> new VersionIndependentConcept(theCodeSystem, c.getCode())));
}
if (codeOpt != null && codeOpt.isPresent()) {

View File

@ -41,6 +41,11 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
* starvation
*/
ourMaxThreads = (int) (Math.random() * 6.0) + 1;
if ("true".equals(System.getProperty("single_db_connection"))) {
ourMaxThreads = 1;
}
}
private Exception myLastStackTrace;

View File

@ -94,6 +94,11 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
* starvation
*/
int maxThreads = (int) (Math.random() * 6.0) + 1;
if ("true".equals(System.getProperty("single_db_connection"))) {
maxThreads = 1;
}
retVal.setMaxTotal(maxThreads);
return retVal;

View File

@ -43,6 +43,10 @@ public class TestR4Config extends BaseJavaConfigR4 {
*/
if (ourMaxThreads == null) {
ourMaxThreads = (int) (Math.random() * 6.0) + 1;
if ("true".equals(System.getProperty("single_db_connection"))) {
ourMaxThreads = 1;
}
}
}

View File

@ -41,6 +41,11 @@ public class TestR5Config extends BaseJavaConfigR5 {
*/
if (ourMaxThreads == null) {
ourMaxThreads = (int) (Math.random() * 6.0) + 1;
if ("true".equals(System.getProperty("single_db_connection"))) {
ourMaxThreads = 1;
}
}
}

View File

@ -43,6 +43,7 @@ import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.jdbc.Work;
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.dstu3.model.Resource;
import org.hl7.fhir.instance.model.api.IBaseBundle;
@ -133,7 +134,8 @@ public abstract class BaseJpaTest extends BaseTest {
@Qualifier(BaseConfig.JPA_VALIDATION_SUPPORT)
@Autowired
private IValidationSupport myJpaPersistedValidationSupport;
@Autowired
private FhirInstanceValidator myFhirInstanceValidator;
@After
public void afterPerformCleanup() {
@ -150,7 +152,9 @@ public abstract class BaseJpaTest extends BaseTest {
if (myJpaPersistedValidationSupport != null) {
ProxyUtil.getSingletonTarget(myJpaPersistedValidationSupport, JpaPersistedResourceValidationSupport.class).clearCaches();
}
if (myFhirInstanceValidator != null) {
myFhirInstanceValidator.invalidateCaches();
}
}

View File

@ -145,7 +145,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseJpaR4Test {
// Validate once
myCaptureQueriesListener.clear();
myObservationDao.validate(obs, null, null, null, null, null, null);
assertEquals(myCaptureQueriesListener.logSelectQueriesForCurrentThread(), 10, myCaptureQueriesListener.getSelectQueriesForCurrentThread().size());
assertEquals(myCaptureQueriesListener.logSelectQueriesForCurrentThread(), 9, myCaptureQueriesListener.getSelectQueriesForCurrentThread().size());
assertEquals(myCaptureQueriesListener.logUpdateQueriesForCurrentThread(), 0, myCaptureQueriesListener.getUpdateQueriesForCurrentThread().size());
assertEquals(myCaptureQueriesListener.logInsertQueriesForCurrentThread(), 0, myCaptureQueriesListener.getInsertQueriesForCurrentThread().size());
assertEquals(myCaptureQueriesListener.logDeleteQueriesForCurrentThread(), 0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());

View File

@ -1,12 +1,16 @@
package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl;
import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc;
import ca.uhn.fhir.jpa.term.api.ITermReadSvc;
import ca.uhn.fhir.jpa.term.custom.CustomTerminologySet;
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChain;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.ValidationModeEnum;
@ -23,9 +27,27 @@ import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.AllergyIntolerance;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.r4.model.CanonicalType;
import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.Condition;
import org.hl7.fhir.r4.model.DateTimeType;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Narrative;
import org.hl7.fhir.r4.model.Observation;
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
import org.hl7.fhir.r4.model.OperationOutcome;
import org.hl7.fhir.r4.model.Organization;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Questionnaire;
import org.hl7.fhir.r4.model.QuestionnaireResponse;
import org.hl7.fhir.r4.model.Reference;
import org.hl7.fhir.r4.model.StringType;
import org.hl7.fhir.r4.model.StructureDefinition;
import org.hl7.fhir.r4.model.ValueSet;
import org.hl7.fhir.r5.utils.IResourceValidator;
import org.junit.After;
import org.junit.AfterClass;
@ -33,6 +55,7 @@ import org.junit.Ignore;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.util.AopTestUtils;
import org.springframework.transaction.PlatformTransactionManager;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@ -45,6 +68,9 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4ValidateTest.class);
@ -56,6 +82,10 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
private ITermCodeSystemStorageSvc myTermCodeSystemStorageSvcc;
@Autowired
private DaoRegistry myDaoRegistry;
@Autowired
private JpaValidationSupportChain myJpaValidationSupportChain;
@Autowired
private PlatformTransactionManager myTransactionManager;
/**
* Create a loinc valueset that expands to more results than the expander is willing to do
@ -155,13 +185,11 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
}
/**
* Per: https://chat.fhir.org/#narrow/stream/179166-implementers/topic/Handling.20incomplete.20CodeSystems
*
* <p>
* We should generate a warning if a code can't be found but the codesystem is a fragment
*/
@Test
@ -219,7 +247,6 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
}
}
/**
* Create a loinc valueset that expands to more results than the expander is willing to do
* in memory, and make sure we can still validate correctly, even if we're using
@ -303,6 +330,115 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
}
/**
* Make sure that we do something sane when validating throws an unexpected exception
*/
@Test
public void testValidate_ValidationSupportThrowsException() {
IValidationSupport validationSupport = mock(IValidationSupport.class);
when(validationSupport.validateCodeInValueSet(any(), any(), any(), any(), any(), any())).thenAnswer(t -> {
// This will fail with a constraint error
try {
myResourceTableDao.save(new ResourceTable());
myResourceTableDao.flush();
} catch (Exception e) {
ourLog.info("Hit expected exception: {}", e.toString());
}
return null;
});
when(validationSupport.getFhirContext()).thenReturn(myFhirCtx);
myJpaValidationSupportChain.addValidationSupport(0, validationSupport);
try {
Observation obs = new Observation();
obs.getText().setDivAsString("<div>Hello</div>");
obs.getCategoryFirstRep().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/observation-category").setCode("vital-signs");
obs.setSubject(new Reference("Patient/123"));
obs.addPerformer(new Reference("Practitioner/123"));
obs.setEffective(DateTimeType.now());
obs.setStatus(ObservationStatus.FINAL);
obs.setValue(new StringType("This is the value"));
OperationOutcome oo;
// Valid code
obs.getText().setStatus(Narrative.NarrativeStatus.GENERATED);
obs.getCode().getCodingFirstRep().setSystem("http://loinc.org").setCode("CODE3").setDisplay("Display 3");
oo = validateAndReturnOutcome(obs);
assertEquals(encode(oo), "No issues detected during validation", oo.getIssueFirstRep().getDiagnostics());
} finally {
myJpaValidationSupportChain.removeValidationSupport(validationSupport);
}
}
/**
* Make sure that we do something sane when validating throws an unexpected exception
*/
@Test
@Ignore
public void testValidate_TermSvcHasDatabaseRollback() {
BaseTermReadSvcImpl.setInvokeOnNextCallForUnitTest(() -> {
try {
myResourceTableDao.save(new ResourceTable());
myResourceTableDao.flush();
} catch (Exception e) {
ourLog.info("Hit expected exception: {}", e.toString());
}
});
Observation obs = new Observation();
obs.getText().setDivAsString("<div>Hello</div>");
obs.getCategoryFirstRep().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/observation-category").setCode("vital-signs");
obs.setSubject(new Reference("Patient/123"));
obs.addPerformer(new Reference("Practitioner/123"));
obs.setEffective(DateTimeType.now());
obs.setStatus(ObservationStatus.FINAL);
obs.setValue(new StringType("This is the value"));
OperationOutcome oo;
// Valid code
obs.getText().setStatus(Narrative.NarrativeStatus.GENERATED);
obs.getCode().getCodingFirstRep().setSystem("http://loinc.org").setCode("CODE3").setDisplay("Display 3");
oo = validateAndReturnOutcome(obs);
assertEquals(encode(oo), "No issues detected during validation", oo.getIssueFirstRep().getDiagnostics());
}
/**
* Make sure that we do something sane when validating throws an unexpected exception
*/
@Test
public void testValidate_TermSvcHasNpe() {
BaseTermReadSvcImpl.setInvokeOnNextCallForUnitTest(() -> {
throw new NullPointerException("MY ERROR");
});
Observation obs = new Observation();
obs.getText().setDivAsString("<div>Hello</div>");
obs.getCategoryFirstRep().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/observation-category").setCode("vital-signs");
obs.setSubject(new Reference("Patient/123"));
obs.addPerformer(new Reference("Practitioner/123"));
obs.setEffective(DateTimeType.now());
obs.setStatus(ObservationStatus.FINAL);
obs.setValue(new StringType("This is the value"));
OperationOutcome oo;
// Valid code
obs.getText().setStatus(Narrative.NarrativeStatus.GENERATED);
obs.getCode().getCodingFirstRep().setSystem("http://loinc.org").setCode("CODE99999").setDisplay("Display 3");
try {
validateAndReturnOutcome(obs);
fail();
} catch (NullPointerException e) {
assertEquals("MY ERROR", e.getMessage());
}
}
@Test
public void testValidateCodeableConceptWithNoSystem() {
AllergyIntolerance allergy = new AllergyIntolerance();
@ -605,6 +741,8 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());
myDaoConfig.setMaximumExpansionSize(DaoConfig.DEFAULT_MAX_EXPANSION_SIZE);
myDaoConfig.setPreExpandValueSets(new DaoConfig().isPreExpandValueSets());
BaseTermReadSvcImpl.setInvokeOnNextCallForUnitTest(null);
}
@Test

View File

@ -4,6 +4,7 @@ import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.dao.data.INpmPackageVersionDao;
import ca.uhn.fhir.jpa.dao.dstu3.BaseJpaDstu3Test;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.test.utilities.JettyUtil;
import ca.uhn.fhir.test.utilities.ProxyUtil;
import org.eclipse.jetty.server.Server;
@ -30,9 +31,9 @@ import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class IgInstallerTestDstu3 extends BaseJpaDstu3Test {
public class IgInstallerDstu3Test extends BaseJpaDstu3Test {
private static final Logger ourLog = LoggerFactory.getLogger(IgInstallerTestDstu3.class);
private static final Logger ourLog = LoggerFactory.getLogger(IgInstallerDstu3Test.class);
@Autowired
private DaoConfig daoConfig;
@Autowired
@ -185,7 +186,7 @@ public class IgInstallerTestDstu3 extends BaseJpaDstu3Test {
);
fail();
} catch (InvalidRequestException e) {
assertEquals("", e.getMessage());
assertEquals("Package ID nictiz.fhir.nl.stu3.questionnaires doesn't match expected: blah", e.getMessage());
}
}
@ -199,8 +200,8 @@ public class IgInstallerTestDstu3 extends BaseJpaDstu3Test {
.setPackageUrl("http://localhost:" + myPort + "/foo.tgz")
);
fail();
} catch (InvalidRequestException e) {
assertEquals("", e.getMessage());
} catch (ResourceNotFoundException e) {
assertEquals("Received HTTP 404 from URL: http://localhost:" + myPort + "/foo.tgz", e.getMessage());
}
}

View File

@ -19,7 +19,7 @@ public class JpaPackageCacheTest extends BaseJpaR4Test {
@Test
public void testSavePackage() throws IOException {
try (InputStream stream = IgInstallerTestDstu3.class.getResourceAsStream("/packages/basisprofil.de.tar.gz")) {
try (InputStream stream = IgInstallerDstu3Test.class.getResourceAsStream("/packages/basisprofil.de.tar.gz")) {
myPackageCacheManager.addPackageToCache("basisprofil.de", "0.2.40", stream, "basisprofil.de");
}

View File

@ -0,0 +1,25 @@
package ca.uhn.fhir.jpa.util;
import org.junit.Test;
import static org.junit.Assert.fail;
public class JpaClasspathTest {
/**
* Make sure no dependencies start bringing in log4j - This makes hibernate decide to start using log4j instead of
* slf4j which is super annoying..
*/
@Test
public void testNoLog4jOnClasspath() {
try {
Class.forName("org.apache.logging.log4j.status.StatusLogger");
fail("org.apache.logging.log4j.status.StatusLogger" + " found on classpath - Make sure log4j isn't being introduced");
} catch (ClassNotFoundException theE) {
// good
}
}
}

View File

@ -122,6 +122,14 @@ public class ValidationSupportChain implements IValidationSupport {
myChain.add(theIndex, theValidationSupport);
}
/**
* Removes an item from the chain. Note that this method is mostly intended for testing. Removing items from the chain while validation is
* actually occurring is not an expected use case for this class.
*/
public void removeValidationSupport(IValidationSupport theValidationSupport) {
myChain.remove(theValidationSupport);
}
@Override
public ValueSetExpansionOutcome expandValueSet(ValidationSupportContext theValidationSupportContext, ValueSetExpansionOptions theExpansionOptions, IBaseResource theValueSetToExpand) {
for (IValidationSupport next : myChain) {

View File

@ -309,7 +309,9 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IInsta
*/
public void invalidateCaches() {
myValidationSupport.invalidateCaches();
myWrappedWorkerContext.invalidateCaches();
if (myWrappedWorkerContext != null) {
myWrappedWorkerContext.invalidateCaches();
}
}