Add tests

This commit is contained in:
jamesagnew 2016-04-14 06:36:29 -04:00
parent 5309e1cebe
commit 0780b7e472
10 changed files with 230 additions and 25 deletions

View File

@ -41,12 +41,14 @@ import ca.uhn.fhir.rest.annotation.TransactionParam;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.param.ResourceParameter;
import ca.uhn.fhir.rest.param.TransactionParameter;
import ca.uhn.fhir.rest.param.TransactionParameter.ParamStyle;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.IRestfulServer;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
public class TransactionMethodBinding extends BaseResourceReturningMethodBinding {
@ -176,6 +178,23 @@ public class TransactionMethodBinding extends BaseResourceReturningMethodBinding
return retVal;
}
@Override
protected void populateActionRequestDetailsForInterceptor(RequestDetails theRequestDetails, ActionRequestDetails theDetails, Object[] theMethodParams) {
super.populateActionRequestDetailsForInterceptor(theRequestDetails, theDetails, theMethodParams);
/*
* If the method has no parsed resource parameter, we parse here in order to have something for the interceptor.
*/
if (myTransactionParamIndex != -1) {
theDetails.setResource((IBaseResource) theMethodParams[myTransactionParamIndex]);
} else {
Class<? extends IBaseResource> resourceType = getContext().getResourceDefinition("Bundle").getImplementingClass();
theDetails.setResource(ResourceParameter.parseResourceFromRequest(theRequestDetails, this, resourceType));
}
}
public static BaseHttpClientInvocation createTransactionInvocation(Bundle theBundle, FhirContext theContext) {
return new HttpPostClientInvocation(theContext, theBundle);
}

View File

@ -23,12 +23,14 @@ package ca.uhn.fhir.rest.server.interceptor.auth;
import java.util.Collection;
import java.util.Set;
import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.util.BundleUtil;
import ca.uhn.fhir.util.FhirTerser;
class Rule implements IAuthRule {
@ -59,8 +61,13 @@ class Rule implements IAuthRule {
case WRITE:
appliesTo = theInputResource;
break;
case BATCH:
case TRANSACTION:
return myMode;
if (requestAppliesToTransaction(ctx, myOp, theInputResource)) {
return myMode;
} else {
return RuleVerdictEnum.NO_DECISION;
}
case ALLOW_ALL:
return RuleVerdictEnum.ALLOW;
case DENY_ALL:
@ -111,6 +118,19 @@ class Rule implements IAuthRule {
return myMode;
}
private boolean requestAppliesToTransaction(FhirContext theContext, RuleOpEnum theOp, IBaseResource theInputResource) {
IBaseBundle request = (IBaseBundle) theInputResource;
String bundleType = BundleUtil.getBundleType(theContext, request);
switch (theOp) {
case TRANSACTION:
return "transaction".equals(bundleType);
case BATCH:
return "batch".equals(bundleType);
default:
return false;
}
}
@Override
public String getName() {
return myName;

View File

@ -26,5 +26,6 @@ enum RuleOpEnum {
ALLOW_ALL,
DENY_ALL,
TRANSACTION,
METADATA
METADATA,
BATCH
}

View File

@ -31,7 +31,6 @@ import org.hl7.fhir.instance.model.api.IPrimitiveType;
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
@ -98,4 +97,15 @@ public class BundleUtil {
return retVal;
}
public static String getBundleType(FhirContext theContext, IBaseBundle theBundle) {
RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
BaseRuntimeChildDefinition entryChild = def.getChildByName("type");
List<IBase> entries = entryChild.getAccessor().getValues(theBundle);
if (entries.size() > 0) {
IPrimitiveType<?> typeElement = (IPrimitiveType<?>) entries.get(0);
return typeElement.getValueAsString();
}
return null;
}
}

View File

@ -13,7 +13,7 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
public class LoadingValidationSupportDstu2 implements IValidationSupport {
private static FhirContext myCtx = FhirContext.forDstu2Hl7Org();
private FhirContext myCtx = FhirContext.forDstu2Hl7Org();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(LoadingValidationSupportDstu2.class);

View File

@ -14,7 +14,7 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
public class LoadingValidationSupportDstu3 implements IValidationSupport {
private static FhirContext myCtx = FhirContext.forDstu3();
private FhirContext myCtx = FhirContext.forDstu3();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(LoadingValidationSupportDstu3.class);

View File

@ -31,11 +31,11 @@ import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
@SuppressWarnings("unused")
public class FhirResourceDaoDstu1Test extends BaseJpaTest {
private static AnnotationConfigApplicationContext ourCtx;
private static AnnotationConfigApplicationContext ourAppCtx;
private static IFhirResourceDao<Device> ourDeviceDao;
private static IFhirResourceDao<DiagnosticReport> ourDiagnosticReportDao;
private static IFhirResourceDao<Encounter> ourEncounterDao;
private static FhirContext ourFhirCtx;
private static FhirContext ourCtx;
private static IFhirResourceDao<Location> ourLocationDao;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu1Test.class);
private static IFhirResourceDao<Observation> ourObservationDao;
@ -126,21 +126,30 @@ public class FhirResourceDaoDstu1Test extends BaseJpaTest {
@AfterClass
public static void afterClass() {
ourCtx.close();
ourAppCtx.close();
ourAppCtx = null;
ourCtx = null;
ourDeviceDao = null;
ourDiagnosticReportDao = null;
ourEncounterDao = null;
ourLocationDao = null;
ourObservationDao = null;
ourOrganizationDao = null;
ourPatientDao = null;
}
@SuppressWarnings("unchecked")
@BeforeClass
public static void beforeClass() {
ourCtx = new AnnotationConfigApplicationContext(TestDstu1Config.class);
ourPatientDao = ourCtx.getBean("myPatientDaoDstu1", IFhirResourceDao.class);
ourObservationDao = ourCtx.getBean("myObservationDaoDstu1", IFhirResourceDao.class);
ourDiagnosticReportDao = ourCtx.getBean("myDiagnosticReportDaoDstu1", IFhirResourceDao.class);
ourDeviceDao = ourCtx.getBean("myDeviceDaoDstu1", IFhirResourceDao.class);
ourOrganizationDao = ourCtx.getBean("myOrganizationDaoDstu1", IFhirResourceDao.class);
ourLocationDao = ourCtx.getBean("myLocationDaoDstu1", IFhirResourceDao.class);
ourEncounterDao = ourCtx.getBean("myEncounterDaoDstu1", IFhirResourceDao.class);
ourFhirCtx = ourCtx.getBean(FhirContext.class);
ourAppCtx = new AnnotationConfigApplicationContext(TestDstu1Config.class);
ourDeviceDao = ourAppCtx.getBean("myDeviceDaoDstu1", IFhirResourceDao.class);
ourDiagnosticReportDao = ourAppCtx.getBean("myDiagnosticReportDaoDstu1", IFhirResourceDao.class);
ourEncounterDao = ourAppCtx.getBean("myEncounterDaoDstu1", IFhirResourceDao.class);
ourLocationDao = ourAppCtx.getBean("myLocationDaoDstu1", IFhirResourceDao.class);
ourObservationDao = ourAppCtx.getBean("myObservationDaoDstu1", IFhirResourceDao.class);
ourOrganizationDao = ourAppCtx.getBean("myOrganizationDaoDstu1", IFhirResourceDao.class);
ourPatientDao = ourAppCtx.getBean("myPatientDaoDstu1", IFhirResourceDao.class);
ourCtx = ourAppCtx.getBean(FhirContext.class);
}
}

View File

@ -5,7 +5,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
@ -18,7 +17,6 @@ import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@ -27,14 +25,9 @@ import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu2.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu2.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.param.DateAndListParam;
import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.util.PortUtil;
@ -57,7 +50,7 @@ public class SearchWithGenericListDstu2Test {
*/
@Test
public void testSearch() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo");
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo&_pretty=true");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
@ -65,6 +58,7 @@ public class SearchWithGenericListDstu2Test {
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals("searchByIdentifier", ourLastMethod);
assertThat(responseContent, containsString("<family value=\"FAMILY\""));
assertThat(responseContent, containsString("<fullUrl value=\"http://localhost:" + ourPort + "/Patient/1\"/>"));
}

View File

@ -177,6 +177,42 @@ public class AuthorizationInterceptorDstu2Test {
assertEquals(200, status.getStatusLine().getStatusCode());
}
@Test
public void testBatchWhenTransactionAllowed() throws Exception {
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
//@formatter:off
return new RuleBuilder()
.allow("Rule 1").transaction().withAnyOperation().andApplyNormalRules().andThen()
.allow("Rule 2").write().allResources().inCompartment("Patient", new IdDt("Patient/1")).andThen()
.allow("Rule 2").read().allResources().inCompartment("Patient", new IdDt("Patient/1")).andThen()
.build();
//@formatter:on
}
});
Bundle input = new Bundle();
input.setType(BundleTypeEnum.BATCH);
input.addEntry().setResource(createPatient(1)).getRequest().setUrl("/Patient");
Bundle output = new Bundle();
output.setType(BundleTypeEnum.TRANSACTION_RESPONSE);
output.addEntry().getResponse().setLocation("/Patient/1");
HttpPost httpPost;
HttpResponse status;
String response;
ourReturn = Arrays.asList((IResource)output);
ourHitMethod = false;
httpPost = new HttpPost("http://localhost:" + ourPort + "/");
httpPost.setEntity(createFhirResourceEntity(input));
status = ourClient.execute(httpPost);
extractResponseAndClose(status);
assertEquals(401, status.getStatusLine().getStatusCode());
}
@Test
public void testMetadataDeny() throws Exception {
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.ALLOW) {

View File

@ -0,0 +1,116 @@
package ca.uhn.fhir.rest.server;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.util.ArrayList;
import java.util.List;
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.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.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu2.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.util.PortUtil;
public class SearchWithGenericListHl7OrgDstu2Test {
private static CloseableHttpClient ourClient;
private static FhirContext ourCtx = FhirContext.forDstu2();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchWithGenericListHl7OrgDstu2Test.class);
private static int ourPort;
private static Server ourServer;
private static String ourLastMethod;
@Before
public void before() {
ourLastMethod = null;
}
/**
* See #291
*/
@Test
public void testSearch() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo&_pretty=true");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals("searchByIdentifier", ourLastMethod);
assertThat(responseContent, containsString("<family value=\"FAMILY\""));
assertThat(responseContent, containsString("<fullUrl value=\"http://localhost:" + ourPort + "/Patient/1\"/>"));
}
@AfterClass
public static void afterClass() throws Exception {
ourServer.stop();
}
@BeforeClass
public static void beforeClass() throws Exception {
ourPort = PortUtil.findFreePort();
ourServer = new Server(ourPort);
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
ServletHandler proxyHandler = new ServletHandler();
RestfulServer servlet = new RestfulServer(ourCtx);
servlet.setPagingProvider(new FifoMemoryPagingProvider(10));
servlet.setResourceProviders(patientProvider);
ServletHolder servletHolder = new ServletHolder(servlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler);
ourServer.start();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setConnectionManager(connectionManager);
ourClient = builder.build();
}
public static class DummyPatientResourceProvider implements IResourceProvider {
@Override
public Class<? extends IResource> getResourceType() {
return Patient.class;
}
//@formatter:off
@SuppressWarnings("rawtypes")
@Search()
public List searchByIdentifier(
@RequiredParam(name=Patient.SP_IDENTIFIER) TokenParam theIdentifier) {
ourLastMethod = "searchByIdentifier";
ArrayList<Patient> retVal = new ArrayList<Patient>();
retVal.add((Patient) new Patient().addName(new HumanNameDt().addFamily("FAMILY")).setId("1"));
return retVal;
}
//@formatter:on
}
}