Fix web testing UI regression

This commit is contained in:
James Agnew 2016-09-06 17:59:04 -04:00
parent 6b9f8ec487
commit 202a1ea885
16 changed files with 450 additions and 119 deletions

View File

@ -21,5 +21,5 @@ package ca.uhn.fhir.rest.api;
*/
public enum RequestTypeEnum {
CONNECT, DELETE, GET, OPTIONS, PATCH, POST, PUT, TRACE, TRACK
CONNECT, DELETE, GET, OPTIONS, PATCH, POST, PUT, TRACE, TRACK, HEAD
}

View File

@ -44,6 +44,7 @@ public class BanUnsupportedHttpMethodsInterceptor extends InterceptorAdapter {
myAllowedMethods.add(RequestTypeEnum.DELETE);
myAllowedMethods.add(RequestTypeEnum.PUT);
myAllowedMethods.add(RequestTypeEnum.POST);
myAllowedMethods.add(RequestTypeEnum.HEAD);
}
@Override

View File

@ -194,7 +194,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
private FhirContext myContext;
// @PersistenceContext(name = "FHIR_UT", type = PersistenceContextType.TRANSACTION, unitName = "FHIR_UT")
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
protected EntityManager myEntityManager;
@ -669,7 +668,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
}
}
private String parseContentTextIntoWords(IBaseResource theResource) {
public String parseContentTextIntoWords(IBaseResource theResource) {
StringBuilder retVal = new StringBuilder();
@SuppressWarnings("rawtypes")
List<IPrimitiveType> childElements = getContext().newTerser().getAllPopulatedChildElementsOfType(theResource, IPrimitiveType.class);
@ -686,6 +685,17 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
return retVal.toString();
}
@Override
public void populateFullTextFields(final IBaseResource theResource, ResourceTable theEntity) {
if (theEntity.getDeleted() != null) {
theEntity.setNarrativeTextParsedIntoWords(null);
theEntity.setContentTextParsedIntoWords(null);
} else {
theEntity.setNarrativeTextParsedIntoWords(parseNarrativeTextIntoWords(theResource));
theEntity.setContentTextParsedIntoWords(parseContentTextIntoWords(theResource));
}
}
private void populateResourceId(final IBaseResource theResource, BaseHasResource theEntity) {
IIdType id = theEntity.getIdDt();
if (getContext().getVersion().getVersion().isRi()) {
@ -931,10 +941,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
throw new NotImplementedException("");
}
public void setConfig(DaoConfig theConfig) {
myConfig = theConfig;
}
// protected MetaDt toMetaDt(Collection<TagDefinition> tagDefinitions) {
// MetaDt retVal = new MetaDt();
// for (TagDefinition next : tagDefinitions) {
@ -953,6 +959,10 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
// return retVal;
// }
public void setConfig(DaoConfig theConfig) {
myConfig = theConfig;
}
@Autowired
public void setContext(FhirContext theContext) {
myContext = theContext;
@ -1273,8 +1283,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
theEntity.setResourceLinks(links);
theEntity.setHasLinks(links.isEmpty() == false);
theEntity.setIndexStatus(INDEX_STATUS_INDEXED);
theEntity.setNarrativeTextParsedIntoWords(parseNarrativeTextIntoWords(theResource));
theEntity.setContentTextParsedIntoWords(parseContentTextIntoWords(theResource));
populateFullTextFields(theResource, theEntity);
} else {
@ -1397,53 +1406,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
return updateEntity(theResource, entity, theDeletedTimestampOrNull, true, true, theUpdateTime);
}
protected void validateDeleteConflictsEmptyOrThrowException(List<DeleteConflict> theDeleteConflicts) {
if (theDeleteConflicts.isEmpty()) {
return;
}
IBaseOperationOutcome oo = OperationOutcomeUtil.newInstance(getContext());
for (DeleteConflict next : theDeleteConflicts) {
String msg = "Unable to delete " + next.getTargetId().toUnqualifiedVersionless().getValue()
+ " because at least one resource has a reference to this resource. First reference found was resource " + next.getTargetId().toUnqualifiedVersionless().getValue() + " in path "
+ next.getSourcePath();
OperationOutcomeUtil.addIssue(getContext(), oo, OO_SEVERITY_ERROR, msg, null, "processing");
}
throw new ResourceVersionConflictException("Delete failed because of constraint failure", oo);
}
/**
* This method is invoked immediately before storing a new resource, or an update to an existing resource to allow the DAO to ensure that it is valid for persistence. By default, checks for the
* "subsetted" tag and rejects resources which have it. Subclasses should call the superclass implementation to preserve this check.
*
* @param theResource
* The resource that is about to be persisted
* @param theEntityToSave
* TODO
*/
protected void validateResourceForStorage(T theResource, ResourceTable theEntityToSave) {
Object tag = null;
if (theResource instanceof IResource) {
IResource res = (IResource) theResource;
TagList tagList = ResourceMetadataKeyEnum.TAG_LIST.get(res);
if (tagList != null) {
tag = tagList.getTag(Constants.TAG_SUBSETTED_SYSTEM, Constants.TAG_SUBSETTED_CODE);
}
} else {
IAnyResource res = (IAnyResource) theResource;
tag = res.getMeta().getTag(Constants.TAG_SUBSETTED_SYSTEM, Constants.TAG_SUBSETTED_CODE);
}
if (tag != null) {
throw new UnprocessableEntityException("Resource contains the 'subsetted' tag, and must not be stored as it may contain a subset of available data");
}
String resName = getContext().getResourceDefinition(theResource).getName();
validateChildReferences(theResource, resName);
}
private void validateChildReferences(IBase theElement, String thePath) {
if (theElement == null) {
return;
@ -1499,6 +1461,53 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
}
}
protected void validateDeleteConflictsEmptyOrThrowException(List<DeleteConflict> theDeleteConflicts) {
if (theDeleteConflicts.isEmpty()) {
return;
}
IBaseOperationOutcome oo = OperationOutcomeUtil.newInstance(getContext());
for (DeleteConflict next : theDeleteConflicts) {
String msg = "Unable to delete " + next.getTargetId().toUnqualifiedVersionless().getValue()
+ " because at least one resource has a reference to this resource. First reference found was resource " + next.getTargetId().toUnqualifiedVersionless().getValue() + " in path "
+ next.getSourcePath();
OperationOutcomeUtil.addIssue(getContext(), oo, OO_SEVERITY_ERROR, msg, null, "processing");
}
throw new ResourceVersionConflictException("Delete failed because of constraint failure", oo);
}
/**
* This method is invoked immediately before storing a new resource, or an update to an existing resource to allow the DAO to ensure that it is valid for persistence. By default, checks for the
* "subsetted" tag and rejects resources which have it. Subclasses should call the superclass implementation to preserve this check.
*
* @param theResource
* The resource that is about to be persisted
* @param theEntityToSave
* TODO
*/
protected void validateResourceForStorage(T theResource, ResourceTable theEntityToSave) {
Object tag = null;
if (theResource instanceof IResource) {
IResource res = (IResource) theResource;
TagList tagList = ResourceMetadataKeyEnum.TAG_LIST.get(res);
if (tagList != null) {
tag = tagList.getTag(Constants.TAG_SUBSETTED_SYSTEM, Constants.TAG_SUBSETTED_CODE);
}
} else {
IAnyResource res = (IAnyResource) theResource;
tag = res.getMeta().getTag(Constants.TAG_SUBSETTED_SYSTEM, Constants.TAG_SUBSETTED_CODE);
}
if (tag != null) {
throw new UnprocessableEntityException("Resource contains the 'subsetted' tag, and must not be stored as it may contain a subset of available data");
}
String resName = getContext().getResourceDefinition(theResource).getName();
validateChildReferences(theResource, resName);
}
protected static boolean isValidPid(IIdType theId) {
if (theId == null || theId.getIdPart() == null) {
return false;

View File

@ -7,6 +7,7 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.entity.BaseHasResource;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum.ResourceMetadataKeySupportingAnyResource;
@ -70,4 +71,6 @@ public interface IDao {
IBaseResource toResource(BaseHasResource theEntity, boolean theForHistoryOperation);
<R extends IBaseResource> R toResource(Class<R> theResourceType, BaseHasResource theEntity, boolean theForHistoryOperation);
void populateFullTextFields(IBaseResource theResource, ResourceTable theEntity);
}

View File

@ -98,6 +98,9 @@ public class JpaValidationSupportDstu3 implements IJpaValidationSupportDstu3 {
search = myValueSetDao.search(ValueSet.SP_URL, new UriParam(theUri));
}
} else if ("StructureDefinition".equals(resourceName)) {
if (theUri.startsWith("http://hl7.org/fhir/StructureDefinition/")) {
return null;
}
search = myStructureDefinitionDao.search(StructureDefinition.SP_URL, new UriParam(theUri));
} else if ("Questionnaire".equals(resourceName)) {
search = myQuestionnaireDao.search(IAnyResource.SP_RES_ID, new StringParam(id.getIdPart()));

View File

@ -77,7 +77,7 @@ import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
@Index(name = "IDX_RES_DATE", columnList="RES_UPDATED"),
@Index(name = "IDX_RES_LANG", columnList="RES_TYPE,RES_LANGUAGE"),
@Index(name = "IDX_RES_PROFILE", columnList="RES_PROFILE"),
@Index(name = "IDX_INDEXSTATUS", columnList="SP_INDEX_STATUS")
@Index(name = "IDX_INDEXSTATUS", columnList="SP_INDEX_STATUS")
})
@AnalyzerDefs({
@AnalyzerDef(name = "autocompleteEdgeAnalyzer",

View File

@ -220,6 +220,8 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
@Autowired
@Qualifier("myValueSetDaoDstu3")
protected IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> myValueSetDao;
@Autowired
protected PlatformTransactionManager myTransactionMgr;
@After()
public void afterGrabCaches() {
ourValueSetDao = myValueSetDao;

View File

@ -30,6 +30,9 @@ import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.AfterClass;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
@ -49,6 +52,36 @@ import ca.uhn.fhir.util.TestUtil;
public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3SearchNoFtTest.class);
@Test
public void testSearchWithRevIncludes() {
final String methodName = "testSearchWithRevIncludes";
TransactionTemplate txTemplate = new TransactionTemplate(myTransactionMgr);
txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW);
IIdType pid = txTemplate.execute(new TransactionCallback<IIdType>() {
@Override
public IIdType doInTransaction(TransactionStatus theStatus) {
org.hl7.fhir.dstu3.model.Patient p = new org.hl7.fhir.dstu3.model.Patient();
p.addName().addFamily(methodName);
IIdType pid = myPatientDao.create(p).getId().toUnqualifiedVersionless();
org.hl7.fhir.dstu3.model.Condition c = new org.hl7.fhir.dstu3.model.Condition();
c.getSubject().setReferenceElement(pid);
myConditionDao.create(c);
return pid;
}
});
SearchParameterMap map = new SearchParameterMap();
map.add(Patient.SP_RES_ID, new StringParam(pid.getIdPart()));
map.addRevInclude(Condition.INCLUDE_PATIENT);
IBundleProvider results = myPatientDao.search(map);
List<IBaseResource> foundResources = results.getResources(0, results.size());
assertEquals(Patient.class, foundResources.get(0).getClass());
assertEquals(Condition.class, foundResources.get(1).getClass());
}
@Test
public void testCodeSearch() {
Subscription subs = new Subscription();
@ -276,7 +309,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
@Test
public void testHasParameter() {
IIdType pid0, pid1;
IIdType pid0;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
@ -287,7 +320,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
patient.addName().addFamily("Tester").addGiven("Joe");
pid1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
}
{
Observation obs = new Observation();
@ -907,6 +940,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
}
}
@SuppressWarnings("deprecation")
@Test
public void testSearchLastUpdatedParamWithComparator() throws InterruptedException {
IIdType id0;
@ -2339,7 +2373,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
ValueSet vs2 = new ValueSet();
vs2.setUrl("http://hl7.org/foo/bar");
IIdType id2 = myValueSetDao.create(vs2, mySrd).getId().toUnqualifiedVersionless();
myValueSetDao.create(vs2, mySrd).getId().toUnqualifiedVersionless();
IBundleProvider result;
result = myValueSetDao.search(ValueSet.SP_URL, new UriParam("http://hl7.org/fhir/ValueSet/basic-resource-type"));

View File

@ -5,31 +5,25 @@ import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.Observation;
import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
import org.hl7.fhir.dstu3.model.OperationOutcome;
import org.hl7.fhir.dstu3.model.Organization;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.StructureDefinition;
import org.hl7.fhir.dstu3.model.ValueSet;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.AfterClass;
import org.junit.Ignore;
import org.junit.Test;
import ca.uhn.fhir.jpa.util.StopWatch;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.ValidationModeEnum;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.TestUtil;
public class FhirResourceDaoDstu3ValidateTest extends BaseJpaDstu3Test {
@ -40,6 +34,31 @@ public class FhirResourceDaoDstu3ValidateTest extends BaseJpaDstu3Test {
TestUtil.clearAllStaticFieldsForUnitTest();
}
@Test
public void testValidateStructureDefinition() throws Exception {
String input = IOUtils.toString(getClass().getResourceAsStream("/sd-david-dhtest7.json"), StandardCharsets.UTF_8);
StructureDefinition sd = myFhirCtx.newJsonParser().parseResource(StructureDefinition.class, input);
ourLog.info("Starting validation");
try {
myStructureDefinitionDao.validate(sd, null, null, null, ValidationModeEnum.UPDATE, null, mySrd);
} catch (PreconditionFailedException e) {
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(e.getOperationOutcome()));
}
ourLog.info("Done validation");
StopWatch sw = new StopWatch();
ourLog.info("Starting validation");
try {
myStructureDefinitionDao.validate(sd, null, null, null, ValidationModeEnum.UPDATE, null, mySrd);
} catch (PreconditionFailedException e) {
// ok
}
ourLog.info("Done validation in {}ms", sw.getMillis());
}
@Test
@Ignore

View File

@ -0,0 +1,243 @@
{
"resourceType": "StructureDefinition",
"id": "dhtest7",
"meta": {
"versionId": "2",
"lastUpdated": "2016-09-01T03:05:36.257-04:00"
},
"url": "http://fhirtest.uhn.ca/baseDstu3/StructureDefinition/dhtest7",
"name": "dhtest7",
"status": "draft",
"experimental": true,
"description": "Base StructureDefinition for Basic Resource",
"requirements": "Need some way to safely (without breaking interoperability) allow implementers to exchange content not supported by the initial set of declared resources.",
"code": [
{
"system": "http://fhir.hl7.org.nz/NamingSystem/application",
"code": "clinfhir"
}
],
"kind": "resource",
"abstract": false,
"baseDefinition": "http://hl7.org/fhir/StructureDefinition/Basic",
"derivation": "constraint",
"snapshot": {
"element": [
{
"path": "Basic",
"short": "Resource for non-supported content",
"definition": "Basic is used for handling concepts not yet defined in FHIR, narrative-only resources that don't map to an existing resource, and custom resources not appropriate for inclusion in the FHIR specification.",
"alias": [
"Z-resource",
"Extension-resource",
"Custom-resource"
],
"min": 0,
"max": "*",
"type": [
{
"code": "DomainResource"
}
],
"isSummary": true,
"mapping": [
{
"identity": "rim",
"map": "Act, Entity or Role"
},
{
"identity": "w5",
"map": "infrastructure.structure"
}
]
},
{
"path": "Basic.id",
"definition": "Id",
"min": 0,
"max": "1",
"base": {
"path": "Resource.id",
"min": 0,
"max": "1"
},
"type": [
{
"code": "id"
}
]
},
{
"path": "Basic.meta",
"definition": "The meta element",
"min": 0,
"max": "1",
"base": {
"path": "Resource.meta",
"min": 0,
"max": "1"
},
"type": [
{
"code": "Meta"
}
]
},
{
"path": "Basic.text",
"definition": "Narrative",
"min": 0,
"max": "1",
"base": {
"path": "DomainResource.text",
"min": 0,
"max": "*"
},
"type": [
{
"code": "Narrative"
}
]
},
{
"path": "Basic.identifier",
"short": "Business identifier",
"definition": "Identifier assigned to the resource for business purposes, outside the context of FHIR.",
"min": 0,
"max": "*",
"type": [
{
"code": "Identifier"
}
],
"isSummary": true,
"mapping": [
{
"identity": "rim",
"map": "./identifier"
},
{
"identity": "w5",
"map": "id"
}
]
},
{
"path": "Basic.code",
"short": "Kind of Resource",
"definition": "Identifies the 'type' of resource - equivalent to the resource name for other resources.",
"comments": "Because resource references will only be able to indicate 'Basic', the type of reference will need to be specified in a Profile identified as part of the resource. Refer to the resource notes section for information on appropriate terminologies for this code.",
"requirements": "Must be able to distinguish different types of \"basic\" resources.",
"min": 1,
"max": "1",
"type": [
{
"code": "CodeableConcept"
}
],
"isModifier": true,
"isSummary": true,
"binding": {
"strength": "example",
"description": "Codes for identifying types of resources not yet defined by FHIR",
"valueSetReference": {
"reference": "http://hl7.org/fhir/ValueSet/basic-resource-type"
}
},
"mapping": [
{
"identity": "rim",
"map": "./code"
},
{
"identity": "w5",
"map": "what"
}
]
},
{
"path": "Basic.subject",
"short": "Identifies the focus of this resource",
"definition": "Identifies the patient, practitioner, device or any other resource that is the \"focus\" of this resource.",
"comments": "Optional as not all resources potential resources will have subjects. Resources associated with multiple subjects can handle this via extension.",
"requirements": "Needed for partitioning the resource by Patient.",
"min": 0,
"max": "1",
"type": [
{
"code": "Reference",
"profile": "http://hl7.org/fhir/StructureDefinition/Resource"
}
],
"isSummary": true,
"mapping": [
{
"identity": "rim",
"map": "./participation[typeCode='SBJ'] (possibly through a ControlAct and Role)"
},
{
"identity": "w5",
"map": "who.focus"
}
]
},
{
"path": "Basic.created",
"short": "When created",
"definition": "Identifies when the resource was first created.",
"requirements": "Allows ordering resource instances by time.",
"min": 0,
"max": "1",
"type": [
{
"code": "date"
}
],
"isSummary": true,
"mapping": [
{
"identity": "rim",
"map": "./participation[typeCode='AUT']/time (possibly through a ControlAct and Role)"
},
{
"identity": "w5",
"map": "when.recorded"
}
]
},
{
"path": "Basic.author",
"short": "Who created",
"definition": "Indicates who was responsible for creating the resource instance.",
"requirements": "Needed for partitioning the resource.",
"min": 0,
"max": "1",
"type": [
{
"code": "Reference",
"profile": "http://hl7.org/fhir/StructureDefinition/Practitioner"
},
{
"code": "Reference",
"profile": "http://hl7.org/fhir/StructureDefinition/Patient"
},
{
"code": "Reference",
"profile": "http://hl7.org/fhir/StructureDefinition/RelatedPerson"
}
],
"isSummary": true,
"mapping": [
{
"identity": "rim",
"map": "./participation[typeCode='SUB'] (possibly through a ControlAct and Role)"
},
{
"identity": "w5",
"map": "who.author"
}
]
}
]
}
}

View File

@ -10,11 +10,7 @@ import org.apache.commons.lang3.time.DateUtils;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.*;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
@ -23,10 +19,8 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu3;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu3;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
import ca.uhn.fhir.rest.server.interceptor.ResponseValidatingInterceptor;
import ca.uhn.fhir.validation.ResultSeverityEnum;
import ca.uhn.fhirtest.interceptor.PublicSecurityInterceptor;
@ -118,33 +112,6 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
return requestValidator;
}
/**
* Bean which validates outgoing responses
*/
@Bean
@Lazy
public ResponseValidatingInterceptor responseValidatingInterceptor() {
ResponseValidatingInterceptor responseValidator = new ResponseValidatingInterceptor();
responseValidator.setResponseHeaderValueNoIssues("Validation did not detect any issues");
responseValidator.setFailOnSeverity(null);
responseValidator.setAddResponseHeaderOnSeverity(null);
responseValidator.setAddResponseOutcomeHeaderOnSeverity(ResultSeverityEnum.INFORMATION);
responseValidator.addExcludeOperationType(RestOperationTypeEnum.METADATA);
responseValidator.addExcludeOperationType(RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE);
responseValidator.addExcludeOperationType(RestOperationTypeEnum.EXTENDED_OPERATION_SERVER);
responseValidator.addExcludeOperationType(RestOperationTypeEnum.EXTENDED_OPERATION_TYPE);
responseValidator.addExcludeOperationType(RestOperationTypeEnum.GET_PAGE);
responseValidator.addExcludeOperationType(RestOperationTypeEnum.HISTORY_INSTANCE);
responseValidator.addExcludeOperationType(RestOperationTypeEnum.HISTORY_SYSTEM);
responseValidator.addExcludeOperationType(RestOperationTypeEnum.HISTORY_TYPE);
responseValidator.addExcludeOperationType(RestOperationTypeEnum.SEARCH_SYSTEM);
responseValidator.addExcludeOperationType(RestOperationTypeEnum.SEARCH_TYPE);
responseValidator.addValidatorModule(instanceValidatorDstu3());
responseValidator.setIgnoreValidatorExceptions(true);
return responseValidator;
}
@Bean(autowire = Autowire.BY_TYPE)
public IServerInterceptor subscriptionSecurityInterceptor() {
return new SubscriptionsRequireManualActivationInterceptorDstu3();

View File

@ -4,6 +4,7 @@ import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
@ -11,6 +12,7 @@ import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpOptions;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
@ -48,7 +50,7 @@ public class ServerFeaturesDstu2Test {
public void testOptions() throws Exception {
HttpOptions httpGet = new HttpOptions("http://localhost:" + ourPort + "");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
@ -60,7 +62,7 @@ public class ServerFeaturesDstu2Test {
httpGet = new HttpOptions("http://localhost:" + ourPort + "/");
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
@ -76,7 +78,7 @@ public class ServerFeaturesDstu2Test {
public void testOptionsForNonBasePath1() throws Exception {
HttpOptions httpGet = new HttpOptions("http://localhost:" + ourPort + "/Foo");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
@ -90,7 +92,7 @@ public class ServerFeaturesDstu2Test {
public void testOptionsForNonBasePath2() throws Exception {
HttpOptions httpGet = new HttpOptions("http://localhost:" + ourPort + "/Patient/1");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
@ -104,7 +106,7 @@ public class ServerFeaturesDstu2Test {
public void testOptionsForNonBasePath3() throws Exception {
HttpOptions httpGet = new HttpOptions("http://localhost:" + ourPort + "/metadata");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
@ -115,18 +117,30 @@ public class ServerFeaturesDstu2Test {
public void testOptionsJson() throws Exception {
HttpOptions httpGet = new HttpOptions("http://localhost:" + ourPort + "?_format=json");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("resourceType\":\"Conformance"));
}
@Test
public void testHeadJson() throws Exception {
HttpHead httpGet = new HttpHead("http://localhost:" + ourPort + "/Patient/123");
HttpResponse status = ourClient.execute(httpGet);
assertEquals(null, status.getEntity());
ourLog.info(status.toString());
assertEquals(400, status.getStatusLine().getStatusCode());
assertThat(status.getFirstHeader("x-powered-by").getValue(), containsString("HAPI"));
}
@Test
public void testRegisterAndUnregisterResourceProviders() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("PRP1"));
@ -140,7 +154,7 @@ public class ServerFeaturesDstu2Test {
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("PRP2"));

View File

@ -1,6 +1,8 @@
package ca.uhn.fhir.rest.server.interceptor;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.net.URI;
import java.util.HashMap;
@ -9,10 +11,7 @@ import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpTrace;
import org.apache.http.client.methods.*;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
@ -56,6 +55,19 @@ public class BanUnsupprtedHttpMethodsInterceptorDstu3Test {
}
}
@Test
public void testHeadJson() throws Exception {
HttpHead httpGet = new HttpHead("http://localhost:" + ourPort + "/Patient/123");
HttpResponse status = ourClient.execute(httpGet);
assertEquals(null, status.getEntity());
ourLog.info(status.toString());
assertEquals(400, status.getStatusLine().getStatusCode());
assertThat(status.getFirstHeader("x-powered-by").getValue(), containsString("HAPI"));
}
@Test
public void testHttpTrackNotEnabled() throws Exception {
HttpRequestBase req = new HttpRequestBase() {

View File

@ -253,8 +253,8 @@
<span class="glyphicon glyphicon-step-backward"></span>
Prev Page
</button>
<script type="text/javascript">
if (<th:block th:text="${riBundle.getLink('prev') == null}"/>) {
<script type="text/javascript" th:inline="javascript">
if ([[${riBundle.getLink('prev') == null}]]) {
$('#page-prev-btn').prop('disabled', true);
}
$('#page-prev-btn').click(function() {
@ -270,8 +270,8 @@
<span class="glyphicon glyphicon-step-forward"></span>
Next Page
</button>
<script type="text/javascript">
if (<th:block th:text="${riBundle.getLink('next') == null}"/>) {
<script type="text/javascript" th:inline="javascript">
if ([[${riBundle.getLink('next') == null}]]) {
$('#page-next-btn').prop('disabled', true);
}
$('#page-next-btn').click(function() {

View File

@ -12,6 +12,18 @@
<![CDATA[<code>_include</code>]]> resources to the response bundle if they were
referred to by a contained reosurce. Thanks to Neal Acharya for reporting!
</action>
<action type="fix">
Fix regression in web testing UI where "prev" and "next" buttons don't work
when showing a result bundle
</action>
<action type="fix">
JPA server should not attempt to resolve built-in FHIR StructureDefinitions from the
database (this causes a significant performance hit when validating)
</action>
<action type="fix">
BanUnsupportedHttpMethodsInterceptor was erroring out when a client
attempts HTTP HEAD requests
</action>
</release>
<release version="2.0" date="2016-08-30">
<action type="fix">

View File

@ -239,6 +239,18 @@ public DaoConfig daoConfig() {
</section>
<section name="Additional Information">
<ul>
<li>
<a href="https://www.openhealthhub.org/t/hapi-terminology-server-uk-snomed-ct-import/592">This page</a>
has information on loading national editions (UK specifically) of SNOMED CT files into
the database.
</li>
</ul>
</section>
<!--
alter table hfj_res_link ALTER COLUMN "TARGET_RESOURCE_ID" NULL;