Correctly handle missing search params with new indexing infrastructure
This commit is contained in:
parent
0c5c347db7
commit
a3687e446e
|
@ -1,6 +1,7 @@
|
|||
package ca.uhn.fhir.util;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
|
@ -365,6 +366,22 @@ public class FhirTerser {
|
|||
for (String nextPath : nextParam.getPathsSplit()) {
|
||||
for (IBaseReference nextValue : getValues(theSource, nextPath, IBaseReference.class)) {
|
||||
String nextRef = nextValue.getReferenceElement().toUnqualifiedVersionless().getValue();
|
||||
|
||||
/*
|
||||
* If the reference isn't an explicit resource ID, but instead is just
|
||||
* a resource object, we'll calculate its ID and treat the target
|
||||
* as that.
|
||||
*/
|
||||
if (isBlank(nextRef) && nextValue.getResource() != null) {
|
||||
IBaseResource nextTarget = nextValue.getResource();
|
||||
IIdType nextTargetId = nextTarget.getIdElement().toUnqualifiedVersionless();
|
||||
if (!nextTargetId.hasResourceType()) {
|
||||
String resourceType = myContext.getResourceDefinition(nextTarget).getName();
|
||||
nextTargetId.setParts(null, resourceType, nextTargetId.getIdPart(), null);
|
||||
}
|
||||
nextRef = nextTargetId.getValue();
|
||||
}
|
||||
|
||||
if (wantRef.equals(nextRef)) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ public class ResourceIndexedSearchParamDate extends BaseResourceIndexedSearchPar
|
|||
* Constructor
|
||||
*/
|
||||
public ResourceIndexedSearchParamDate() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -200,10 +200,14 @@ public class ResourceIndexedSearchParamQuantity extends BaseResourceIndexedSearc
|
|||
b.append("system", getSystem());
|
||||
b.append("units", getUnits());
|
||||
b.append("value", getValue());
|
||||
b.append("missing", isMissing());
|
||||
return b.build();
|
||||
}
|
||||
|
||||
private static String toTruncatedString(BigDecimal theValue) {
|
||||
if (theValue == null) {
|
||||
return null;
|
||||
}
|
||||
return theValue.setScale(0, RoundingMode.FLOOR).toPlainString();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
|
||||
import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test;
|
||||
import ca.uhn.fhir.jpa.rp.r4.ObservationResourceProvider;
|
||||
import ca.uhn.fhir.jpa.rp.r4.OrganizationResourceProvider;
|
||||
import ca.uhn.fhir.jpa.rp.r4.PatientResourceProvider;
|
||||
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.interceptor.SimpleRequestHeaderInterceptor;
|
||||
import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleType;
|
||||
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
|
||||
import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender;
|
||||
import org.junit.*;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class EmptyIndexesR4Test extends BaseJpaR4Test {
|
||||
private static RestfulServer myRestServer;
|
||||
private static IGenericClient ourClient;
|
||||
private static FhirContext ourCtx;
|
||||
private static CloseableHttpClient ourHttpClient;
|
||||
private static Server ourServer;
|
||||
private static String ourServerBase;
|
||||
private SimpleRequestHeaderInterceptor mySimpleHeaderInterceptor;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@After
|
||||
public void after() {
|
||||
myRestServer.setUseBrowserFriendlyContentTypes(true);
|
||||
ourClient.unregisterInterceptor(mySimpleHeaderInterceptor);
|
||||
myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields());
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
mySimpleHeaderInterceptor = new SimpleRequestHeaderInterceptor();
|
||||
ourClient.registerInterceptor(mySimpleHeaderInterceptor);
|
||||
myDaoConfig.setIndexMissingFields(DaoConfig.IndexEnabledEnum.DISABLED);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeStartServer() throws Exception {
|
||||
if (myRestServer == null) {
|
||||
PatientResourceProvider patientRp = new PatientResourceProvider();
|
||||
patientRp.setDao(myPatientDao);
|
||||
|
||||
QuestionnaireResourceProviderR4 questionnaireRp = new QuestionnaireResourceProviderR4();
|
||||
questionnaireRp.setDao(myQuestionnaireDao);
|
||||
|
||||
ObservationResourceProvider observationRp = new ObservationResourceProvider();
|
||||
observationRp.setDao(myObservationDao);
|
||||
|
||||
OrganizationResourceProvider organizationRp = new OrganizationResourceProvider();
|
||||
organizationRp.setDao(myOrganizationDao);
|
||||
|
||||
RestfulServer restServer = new RestfulServer(ourCtx);
|
||||
restServer.setResourceProviders(patientRp, questionnaireRp, observationRp, organizationRp);
|
||||
|
||||
restServer.setPlainProviders(mySystemProvider);
|
||||
|
||||
int myPort = RandomServerPortProvider.findFreePort();
|
||||
ourServer = new Server(myPort);
|
||||
|
||||
ServletContextHandler proxyHandler = new ServletContextHandler();
|
||||
proxyHandler.setContextPath("/");
|
||||
|
||||
ourServerBase = "http://localhost:" + myPort + "/fhir/context";
|
||||
|
||||
ServletHolder servletHolder = new ServletHolder();
|
||||
servletHolder.setServlet(restServer);
|
||||
proxyHandler.addServlet(servletHolder, "/fhir/context/*");
|
||||
|
||||
ourCtx = FhirContext.forR4();
|
||||
restServer.setFhirContext(ourCtx);
|
||||
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourHttpClient = builder.build();
|
||||
|
||||
ourCtx.getRestfulClientFactory().setSocketTimeout(600 * 1000);
|
||||
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
|
||||
ourClient.setLogRequestAndResponse(true);
|
||||
myRestServer = restServer;
|
||||
}
|
||||
|
||||
myRestServer.setDefaultResponseEncoding(EncodingEnum.XML);
|
||||
myRestServer.setPagingProvider(myPagingProvider);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDontCreateNullIndexesWithOnlyString() {
|
||||
Observation obs = new Observation();
|
||||
obs.getCode().setText("ZXCVBNM ASDFGHJKL QWERTYUIOPASDFGHJKL");
|
||||
myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
runInTransaction(()->{
|
||||
assertThat(myResourceIndexedSearchParamQuantityDao.findAll(), empty());
|
||||
assertThat(myResourceIndexedSearchParamTokenDao.findAll(), empty());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDontCreateNullIndexesWithOnlyToken() {
|
||||
Observation obs = new Observation();
|
||||
obs.getCode().addCoding().setSystem("FOO").setCode("BAR");
|
||||
myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
runInTransaction(()->{
|
||||
assertThat(myResourceIndexedSearchParamQuantityDao.findAll(), empty());
|
||||
assertThat(myResourceIndexedSearchParamStringDao.findAll(), empty());
|
||||
// code and combo-code
|
||||
assertThat(myResourceIndexedSearchParamTokenDao.findAll().toString(), myResourceIndexedSearchParamTokenDao.findAll(), hasSize(2));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourServer.stop();
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,37 +1,11 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.client.methods.*;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleType;
|
||||
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
|
||||
import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.*;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
|
||||
import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test;
|
||||
import ca.uhn.fhir.jpa.rp.r4.*;
|
||||
import ca.uhn.fhir.jpa.rp.r4.ObservationResourceProvider;
|
||||
import ca.uhn.fhir.jpa.rp.r4.OrganizationResourceProvider;
|
||||
import ca.uhn.fhir.jpa.rp.r4.PatientResourceProvider;
|
||||
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
|
@ -45,6 +19,35 @@ import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
|||
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleType;
|
||||
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
|
||||
import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender;
|
||||
import org.junit.*;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class SystemProviderR4Test extends BaseJpaR4Test {
|
||||
|
||||
|
@ -210,7 +213,8 @@ public class SystemProviderR4Test extends BaseJpaR4Test {
|
|||
ourLog.info(output);
|
||||
assertEquals(200, http.getStatusLine().getStatusCode());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(http);;
|
||||
IOUtils.closeQuietly(http);
|
||||
;
|
||||
}
|
||||
|
||||
get = new HttpGet(ourServerBase + "/$perform-reindexing-pass");
|
||||
|
@ -220,7 +224,8 @@ public class SystemProviderR4Test extends BaseJpaR4Test {
|
|||
ourLog.info(output);
|
||||
assertEquals(200, http.getStatusLine().getStatusCode());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(http);;
|
||||
IOUtils.closeQuietly(http);
|
||||
;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -237,6 +242,7 @@ public class SystemProviderR4Test extends BaseJpaR4Test {
|
|||
assertThat(http.getFirstHeader("Content-Type").getValue(), containsString("application/fhir+json"));
|
||||
}
|
||||
|
||||
|
||||
@Transactional(propagation = Propagation.NEVER)
|
||||
@Test
|
||||
public void testSuggestKeywords() throws Exception {
|
||||
|
|
|
@ -390,6 +390,69 @@ public class AuthorizationInterceptorR4Test {
|
|||
assertTrue(ourHitMethod);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllowByCompartmentUsingUnqualifiedIds() throws Exception {
|
||||
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||
@Override
|
||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||
return new RuleBuilder().allow().read().resourcesOfType(CarePlan.class).inCompartment("Patient", new IdType("Patient/123")).andThen().denyAll()
|
||||
.build();
|
||||
}
|
||||
});
|
||||
|
||||
HttpGet httpGet;
|
||||
HttpResponse status;
|
||||
|
||||
Patient patient;
|
||||
CarePlan carePlan;
|
||||
|
||||
// Unqualified
|
||||
patient = new Patient();
|
||||
patient.setId("123");
|
||||
carePlan = new CarePlan();
|
||||
carePlan.setStatus(CarePlan.CarePlanStatus.ACTIVE);
|
||||
carePlan.getSubject().setResource(patient);
|
||||
|
||||
ourHitMethod = false;
|
||||
ourReturn = Collections.singletonList(carePlan);
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/CarePlan/135154");
|
||||
status = ourClient.execute(httpGet);
|
||||
extractResponseAndClose(status);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertTrue(ourHitMethod);
|
||||
|
||||
// Qualified
|
||||
patient = new Patient();
|
||||
patient.setId("Patient/123");
|
||||
carePlan = new CarePlan();
|
||||
carePlan.setStatus(CarePlan.CarePlanStatus.ACTIVE);
|
||||
carePlan.getSubject().setResource(patient);
|
||||
|
||||
ourHitMethod = false;
|
||||
ourReturn = Collections.singletonList(carePlan);
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/CarePlan/135154");
|
||||
status = ourClient.execute(httpGet);
|
||||
extractResponseAndClose(status);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertTrue(ourHitMethod);
|
||||
|
||||
// Wrong one
|
||||
patient = new Patient();
|
||||
patient.setId("456");
|
||||
carePlan = new CarePlan();
|
||||
carePlan.setStatus(CarePlan.CarePlanStatus.ACTIVE);
|
||||
carePlan.getSubject().setResource(patient);
|
||||
|
||||
ourHitMethod = false;
|
||||
ourReturn = Collections.singletonList(carePlan);
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/CarePlan/135154");
|
||||
status = ourClient.execute(httpGet);
|
||||
extractResponseAndClose(status);
|
||||
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||
assertTrue(ourHitMethod);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBatchWhenOnlyTransactionAllowed() throws Exception {
|
||||
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||
|
|
|
@ -248,6 +248,12 @@
|
|||
the number of threads allocated to reindexing may now be adjusted via a
|
||||
setting in the DaoConfig.
|
||||
</action>
|
||||
<action type="fix">
|
||||
AuthorizationInterceptor did not correctly grant access to resources
|
||||
by compartment when the reference on the target resource that pointed
|
||||
to the compartment owner was defined using a resource object (ResourceReference#setResource)
|
||||
instead of a reference (ResourceReference#setReference).
|
||||
</action>
|
||||
</release>
|
||||
<release version="3.3.0" date="2018-03-29">
|
||||
<action type="add">
|
||||
|
|
Loading…
Reference in New Issue