From 106eb75dc64c6283f26a6504c548b308ae0469b4 Mon Sep 17 00:00:00 2001 From: James Agnew Date: Mon, 8 Nov 2021 17:47:56 -0500 Subject: [PATCH] Allow GraphQL to work with RequestValidatingInterceptor (#3145) * Allow GraphQL to work with RequestValidatingInterceptor * Add test * Add changelog --- ...raphql-request-validating-interceptor.yaml | 5 + .../BaseValidatingInterceptor.java | 9 +- .../server/method/GraphQLMethodBinding.java | 3 + .../method/GraphQLQueryBodyParameter.java | 11 +- .../server/ResourceProviderExtension.java | 14 +- .../server/RestfulServerExtension.java | 4 + .../RequestValidatingInterceptorR4Test.java | 197 ++++++++++------ .../ResponseValidatingInterceptorR4Test.java | 222 ++++++++---------- 8 files changed, 258 insertions(+), 207 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_7_0/3145-graphql-request-validating-interceptor.yaml diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_7_0/3145-graphql-request-validating-interceptor.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_7_0/3145-graphql-request-validating-interceptor.yaml new file mode 100644 index 00000000000..ab871d487b6 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_7_0/3145-graphql-request-validating-interceptor.yaml @@ -0,0 +1,5 @@ +--- +type: fix +issue: 3145 +title: "RequestValidatingInteceptor incorrectly prevented GraphQL requests from being submitted using + the HTTP POST form of the GraphQL operation." diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/BaseValidatingInterceptor.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/BaseValidatingInterceptor.java index 3f7a67a0796..5c4083e7529 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/BaseValidatingInterceptor.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/BaseValidatingInterceptor.java @@ -306,10 +306,17 @@ public abstract class BaseValidatingInterceptor extends ValidationResultEnric * Note: May return null */ protected ValidationResult validate(T theRequest, RequestDetails theRequestDetails) { - if (theRequest == null) { + if (theRequest == null || theRequestDetails == null) { return null; } + switch (theRequestDetails.getRestOperationType()) { + case GRAPHQL_REQUEST: + return null; + default: + break; + } + FhirValidator validator; if (myValidator != null) { validator = myValidator; diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/GraphQLMethodBinding.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/GraphQLMethodBinding.java index 35779595f40..b693e02cd71 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/GraphQLMethodBinding.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/GraphQLMethodBinding.java @@ -34,6 +34,7 @@ import ca.uhn.fhir.rest.api.server.ResponseDetails; import ca.uhn.fhir.rest.param.ParameterUtil; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; +import org.apache.commons.lang3.Validate; import org.hl7.fhir.instance.model.api.IBaseResource; import javax.annotation.Nonnull; @@ -109,8 +110,10 @@ public class GraphQLMethodBinding extends OperationMethodBinding { private String getQueryValue(Object[] methodParams) { switch (myMethodRequestType) { case POST: + Validate.notNull(myQueryBodyParamIndex, "GraphQL method does not have @" + GraphQLQueryBody.class.getSimpleName() + " parameter"); return (String) methodParams[myQueryBodyParamIndex]; case GET: + Validate.notNull(myQueryUrlParamIndex, "GraphQL method does not have @" + GraphQLQueryUrl.class.getSimpleName() + " parameter"); return (String) methodParams[myQueryUrlParamIndex]; } return null; diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/GraphQLQueryBodyParameter.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/GraphQLQueryBodyParameter.java index 209cb0ddd42..7440a542a41 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/GraphQLQueryBodyParameter.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/GraphQLQueryBodyParameter.java @@ -44,6 +44,8 @@ import java.util.Collection; import static ca.uhn.fhir.rest.api.Constants.CT_GRAPHQL; import static ca.uhn.fhir.rest.api.Constants.CT_JSON; import static ca.uhn.fhir.rest.server.method.ResourceParameter.createRequestReader; +import static org.apache.commons.lang3.StringUtils.defaultString; +import static org.apache.commons.lang3.StringUtils.trim; public class GraphQLQueryBodyParameter implements IParameter { @@ -51,9 +53,16 @@ public class GraphQLQueryBodyParameter implements IParameter { @Override public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding theMethodBinding) throws InternalErrorException, InvalidRequestException { - String ctValue = theRequest.getHeader(Constants.HEADER_CONTENT_TYPE); + String ctValue = defaultString(theRequest.getHeader(Constants.HEADER_CONTENT_TYPE)); Reader requestReader = createRequestReader(theRequest); + // Trim off "; charset=FOO" from the content-type header + int semicolonIdx = ctValue.indexOf(';'); + if (semicolonIdx != -1) { + ctValue = ctValue.substring(0, semicolonIdx); + } + ctValue = trim(ctValue); + if (CT_JSON.equals(ctValue)) { try { ObjectMapper mapper = new ObjectMapper(); diff --git a/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/server/ResourceProviderExtension.java b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/server/ResourceProviderExtension.java index 704673e52f2..4bc9f4f5569 100644 --- a/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/server/ResourceProviderExtension.java +++ b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/server/ResourceProviderExtension.java @@ -20,19 +20,22 @@ package ca.uhn.fhir.test.utilities.server; * #L% */ +import org.apache.commons.lang3.Validate; import org.junit.jupiter.api.extension.AfterEachCallback; import org.junit.jupiter.api.extension.BeforeEachCallback; import org.junit.jupiter.api.extension.ExtensionContext; -public class ResourceProviderExtension implements BeforeEachCallback, AfterEachCallback { +public class ResourceProviderExtension implements BeforeEachCallback, AfterEachCallback { private final RestfulServerExtension myRestfulServerExtension; - private Object myProvider; + private final T myProvider; /** * Constructor */ - public ResourceProviderExtension(RestfulServerExtension theRestfulServerExtension, Object theProvider) { + public ResourceProviderExtension(RestfulServerExtension theRestfulServerExtension, T theProvider) { + Validate.notNull(theRestfulServerExtension); + Validate.notNull(theProvider); myRestfulServerExtension = theRestfulServerExtension; myProvider = theProvider; } @@ -46,4 +49,9 @@ public class ResourceProviderExtension implements BeforeEachCallback, AfterEachC public void beforeEach(ExtensionContext context) { myRestfulServerExtension.getRestfulServer().registerProvider(myProvider); } + + public T getProvider() { + return myProvider; + } + } diff --git a/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/server/RestfulServerExtension.java b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/server/RestfulServerExtension.java index dd6e22bdfdd..0894e1c8b1e 100644 --- a/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/server/RestfulServerExtension.java +++ b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/server/RestfulServerExtension.java @@ -234,6 +234,10 @@ public class RestfulServerExtension implements BeforeEachCallback, AfterEachCall return "http://localhost:" + myPort; } + public void unregisterAllInterceptors() { + myServlet.getInterceptorService().unregisterAllInterceptors(); + } + @Interceptor private class ListenerExtension { diff --git a/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/RequestValidatingInterceptorR4Test.java b/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/RequestValidatingInterceptorR4Test.java index 1350676b053..0dde2bad246 100644 --- a/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/RequestValidatingInterceptorR4Test.java +++ b/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/RequestValidatingInterceptorR4Test.java @@ -1,21 +1,27 @@ package ca.uhn.fhir.rest.server; import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.rest.annotation.Create; import ca.uhn.fhir.rest.annotation.Delete; +import ca.uhn.fhir.rest.annotation.GraphQL; +import ca.uhn.fhir.rest.annotation.GraphQLQueryBody; +import ca.uhn.fhir.rest.annotation.GraphQLQueryUrl; import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.OptionalParam; import ca.uhn.fhir.rest.annotation.ResourceParam; import ca.uhn.fhir.rest.annotation.Search; import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor; -import ca.uhn.fhir.test.utilities.JettyUtil; +import ca.uhn.fhir.test.utilities.HttpClientExtension; +import ca.uhn.fhir.test.utilities.server.ResourceProviderExtension; +import ca.uhn.fhir.test.utilities.server.RestfulServerExtension; import ca.uhn.fhir.util.TestUtil; +import ca.uhn.fhir.util.UrlUtil; import ca.uhn.fhir.validation.IValidationContext; import ca.uhn.fhir.validation.IValidatorModule; import ca.uhn.fhir.validation.ResultSeverityEnum; @@ -28,29 +34,23 @@ 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.ServletHandler; -import org.eclipse.jetty.servlet.ServletHolder; import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator; import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Narrative; import org.hl7.fhir.r4.model.Patient; import org.hl7.fhir.utilities.xhtml.XhtmlNode; import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; import org.mockito.Mockito; import java.io.IOException; import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; @@ -59,23 +59,27 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; public class RequestValidatingInterceptorR4Test { - private static CloseableHttpClient ourClient; - - private static FhirContext ourCtx = FhirContext.forR4(); - private static boolean ourLastRequestWasSearch; private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RequestValidatingInterceptorR4Test.class); + @RegisterExtension + static HttpClientExtension ourClient = new HttpClientExtension(); + private static final FhirContext ourCtx = FhirContext.forR4Cached(); + + @RegisterExtension + @Order(0) + static RestfulServerExtension ourServlet = new RestfulServerExtension(ourCtx); + @RegisterExtension + @Order(1) + static ResourceProviderExtension ourProvider = new ResourceProviderExtension<>(ourServlet, new PatientProvider()); + private static boolean ourLastRequestWasSearch; private static int ourPort; - - private static Server ourServer; - - private static RestfulServer ourServlet; - private RequestValidatingInterceptor myInterceptor; @BeforeEach public void before() { + ourProvider.getProvider().ourLastGraphQlQueryGet = null; + ourProvider.getProvider().ourLastGraphQlQueryPost = null; ourLastRequestWasSearch = false; - ourServlet.getInterceptorService().unregisterAllInterceptors(); + ourServlet.unregisterAllInterceptors(); myInterceptor = new RequestValidatingInterceptor(); // myInterceptor.setFailOnSeverity(ResultSeverityEnum.ERROR); @@ -84,6 +88,7 @@ public class RequestValidatingInterceptorR4Test { // myInterceptor.setResponseHeaderValue(RequestValidatingInterceptor.DEFAULT_RESPONSE_HEADER_VALUE); ourServlet.registerInterceptor(myInterceptor); + ourPort = ourServlet.getPort(); } @Test @@ -100,7 +105,7 @@ public class RequestValidatingInterceptorR4Test { HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_JSON, "UTF-8"))); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -113,6 +118,41 @@ public class RequestValidatingInterceptorR4Test { assertThat(responseContent, not(containsString(""))); } + @Test + public void testGraphQlRequestResponse_GET() throws IOException { + HttpGet request = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escapeUrlParam("{name}")); + + try (CloseableHttpResponse status = ourClient.getClient().execute(request)) { + String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); + + ourLog.info("Response was:\n{}", status); + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals("{\"name\":{\"family\": \"foo\"}}", responseContent); + assertEquals("{name}", ourProvider.getProvider().ourLastGraphQlQueryGet); + } + + } + + @Test + public void testGraphQlRequestResponse_POST() throws IOException { + HttpPost request = new HttpPost("http://localhost:" + ourPort + "/Patient/123/$graphql"); + request.setEntity(new StringEntity("{\"query\": \"{name}\"}", ContentType.APPLICATION_JSON)); + + try (CloseableHttpResponse status = ourClient.getClient().execute(request)) { + String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); + + ourLog.info("Response was:\n{}", status); + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals("{\"name\":{\"family\": \"foo\"}}", responseContent); + assertEquals("{name}", ourProvider.getProvider().ourLastGraphQlQueryPost); + } + + } + @Test public void testCreateJsonInvalidNoValidatorsSpecified() throws Exception { myInterceptor.setAddResponseHeaderOnSeverity(ResultSeverityEnum.INFORMATION); @@ -126,7 +166,7 @@ public class RequestValidatingInterceptorR4Test { HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_JSON, "UTF-8"))); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -136,7 +176,7 @@ public class RequestValidatingInterceptorR4Test { assertEquals(422, status.getStatusLine().getStatusCode()); assertThat(status.toString(), containsString("X-FHIR-Request-Validation")); - assertThat(responseContent, containsString("\"severity\":\"error\"")); + assertThat(responseContent, containsString("\"severity\": \"error\"")); } @Test @@ -150,7 +190,7 @@ public class RequestValidatingInterceptorR4Test { HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_JSON, "UTF-8"))); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -176,7 +216,7 @@ public class RequestValidatingInterceptorR4Test { HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_JSON, "UTF-8"))); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -188,8 +228,6 @@ public class RequestValidatingInterceptorR4Test { assertThat(status.toString(), (containsString("X-FHIR-Request-Validation: NO ISSUES"))); } - - @Test public void testValidateXmlPayloadWithXxeDirective_InstanceValidator() throws IOException { IValidatorModule module = new FhirInstanceValidator(ourCtx); @@ -213,7 +251,7 @@ public class RequestValidatingInterceptorR4Test { HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); - try (CloseableHttpResponse status = ourClient.execute(httpPost)) { + try (CloseableHttpResponse status = ourClient.getClient().execute(httpPost)) { String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); ourLog.info("Response was:\n{}", status); @@ -225,7 +263,6 @@ public class RequestValidatingInterceptorR4Test { } - @Test public void testCreateXmlInvalidInstanceValidator() throws Exception { IValidatorModule module = new FhirInstanceValidator(ourCtx); @@ -242,7 +279,7 @@ public class RequestValidatingInterceptorR4Test { HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); - try (CloseableHttpResponse status = ourClient.execute(httpPost)) { + try (CloseableHttpResponse status = ourClient.getClient().execute(httpPost)) { String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); ourLog.info("Response was:\n{}", status); @@ -266,7 +303,7 @@ public class RequestValidatingInterceptorR4Test { HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -293,7 +330,7 @@ public class RequestValidatingInterceptorR4Test { HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -305,7 +342,6 @@ public class RequestValidatingInterceptorR4Test { assertThat(status.toString(), containsString("X-FHIR-Request-Validation: {\"resourceType\":\"OperationOutcome")); } - @SuppressWarnings("unchecked") @Test public void testInterceptorExceptionNpeNoIgnore() throws Exception { @@ -317,14 +353,14 @@ public class RequestValidatingInterceptorR4Test { myInterceptor.setIgnoreValidatorExceptions(false); Mockito.doThrow(new NullPointerException("SOME MESSAGE")).when(module).validateResource(Mockito.any(IValidationContext.class)); - + Patient patient = new Patient(); patient.addIdentifier().setValue("002"); String encoded = ourCtx.newXmlParser().encodeResourceToString(patient); HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -347,14 +383,14 @@ public class RequestValidatingInterceptorR4Test { myInterceptor.setIgnoreValidatorExceptions(true); Mockito.doThrow(NullPointerException.class).when(module).validateResource(Mockito.any(IValidationContext.class)); - + Patient patient = new Patient(); patient.addIdentifier().setValue("002"); String encoded = ourCtx.newXmlParser().encodeResourceToString(patient); HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -377,14 +413,14 @@ public class RequestValidatingInterceptorR4Test { myInterceptor.setIgnoreValidatorExceptions(false); Mockito.doThrow(new InternalErrorException("FOO")).when(module).validateResource(Mockito.any(IValidationContext.class)); - + Patient patient = new Patient(); patient.addIdentifier().setValue("002"); String encoded = ourCtx.newXmlParser().encodeResourceToString(patient); HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -407,14 +443,14 @@ public class RequestValidatingInterceptorR4Test { myInterceptor.setIgnoreValidatorExceptions(true); Mockito.doThrow(InternalErrorException.class).when(module).validateResource(Mockito.any(IValidationContext.class)); - + Patient patient = new Patient(); patient.addIdentifier().setValue("002"); String encoded = ourCtx.newXmlParser().encodeResourceToString(patient); HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -437,7 +473,7 @@ public class RequestValidatingInterceptorR4Test { HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); httpPost.setEntity(new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -459,7 +495,7 @@ public class RequestValidatingInterceptorR4Test { HttpDelete httpDelete = new HttpDelete("http://localhost:" + ourPort + "/Patient/123"); - CloseableHttpResponse status = ourClient.execute(httpDelete); + CloseableHttpResponse status = ourClient.getClient().execute(httpDelete); try { ourLog.info("Response was:\n{}", status); @@ -479,7 +515,7 @@ public class RequestValidatingInterceptorR4Test { // This header caused a crash httpGet.addHeader("Content-Type", "application/xml+fhir"); - HttpResponse status = ourClient.execute(httpGet); + HttpResponse status = ourClient.getClient().execute(httpGet); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -495,7 +531,7 @@ public class RequestValidatingInterceptorR4Test { public void testSearch() throws Exception { HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient?foo=bar"); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -508,36 +544,13 @@ public class RequestValidatingInterceptorR4Test { assertEquals(true, ourLastRequestWasSearch); } - @AfterAll - public static void afterClassClearContext() throws Exception { - JettyUtil.closeServer(ourServer); - TestUtil.randomizeLocaleAndTimezone(); - } - - @BeforeAll - public static void beforeClass() throws Exception { - ourServer = new Server(0); - - PatientProvider patientProvider = new PatientProvider(); - - ServletHandler proxyHandler = new ServletHandler(); - ourServlet = new RestfulServer(ourCtx); - ourServlet.setResourceProviders(patientProvider); - ServletHolder servletHolder = new ServletHolder(ourServlet); - proxyHandler.addServletWithMapping(servletHolder, "/*"); - ourServer.setHandler(proxyHandler); - JettyUtil.startServer(ourServer); - ourPort = JettyUtil.getPortForStartedServer(ourServer); - - PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); - HttpClientBuilder builder = HttpClientBuilder.create(); - builder.setConnectionManager(connectionManager); - ourClient = builder.build(); - - } - public static class PatientProvider implements IResourceProvider { + public String ourLastGraphQlQueryGet; + public String ourLastGraphQlQueryPost; + + private IBaseResource myReturnResource; + @Create() public MethodOutcome createPatient(@ResourceParam Patient thePatient, @IdParam IdType theIdParam) { return new MethodOutcome(new IdDt("Patient/001/_history/002")); @@ -548,17 +561,45 @@ public class RequestValidatingInterceptorR4Test { return new MethodOutcome(theId.withVersion("2")); } + @GraphQL(type = RequestTypeEnum.GET) + public String graphQLGet(@IdParam IIdType theId, @GraphQLQueryUrl String theQueryUrl) { + ourLastGraphQlQueryGet = theQueryUrl; + return "{\"name\":{\"family\": \"foo\"}}"; + } + + @GraphQL(type = RequestTypeEnum.POST) + public String graphQLPost(@IdParam IIdType theId, @GraphQLQueryBody String theQueryUrl) { + ourLastGraphQlQueryPost = theQueryUrl; + return "{\"name\":{\"family\": \"foo\"}}"; + } + @Override public Class getResourceType() { return Patient.class; } - @Search - public List search(@OptionalParam(name = "foo") StringParam theString) { - ourLastRequestWasSearch = true; - return new ArrayList(); + public void setReturnResource(IBaseResource theReturnResource) { + myReturnResource = theReturnResource; } + @Search + public ArrayList search(@OptionalParam(name = "foo") StringParam theString) { + ourLastRequestWasSearch = true; + ArrayList retVal = new ArrayList<>(); + if (myReturnResource != null) { + myReturnResource.setId("1"); + retVal.add(myReturnResource); + myReturnResource = null; + } + return retVal; + } + + + } + + @AfterAll + public static void afterClassClearContext() throws Exception { + TestUtil.randomizeLocaleAndTimezone(); } } diff --git a/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/ResponseValidatingInterceptorR4Test.java b/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/ResponseValidatingInterceptorR4Test.java index 068baeadbd3..5701b018a3e 100644 --- a/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/ResponseValidatingInterceptorR4Test.java +++ b/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/ResponseValidatingInterceptorR4Test.java @@ -1,18 +1,13 @@ package ca.uhn.fhir.rest.server; import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.rest.annotation.Delete; -import ca.uhn.fhir.rest.annotation.IdParam; -import ca.uhn.fhir.rest.annotation.OptionalParam; -import ca.uhn.fhir.rest.annotation.Search; -import ca.uhn.fhir.rest.api.EncodingEnum; -import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.RestOperationTypeEnum; -import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.interceptor.ResponseValidatingInterceptor; -import ca.uhn.fhir.test.utilities.JettyUtil; -import ca.uhn.fhir.util.TestUtil; +import ca.uhn.fhir.test.utilities.HttpClientExtension; +import ca.uhn.fhir.test.utilities.server.ResourceProviderExtension; +import ca.uhn.fhir.test.utilities.server.RestfulServerExtension; +import ca.uhn.fhir.util.UrlUtil; import ca.uhn.fhir.validation.IValidationContext; import ca.uhn.fhir.validation.IValidatorModule; import ca.uhn.fhir.validation.ResultSeverityEnum; @@ -22,28 +17,22 @@ import org.apache.http.HttpResponse; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpDelete; 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.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; import org.hamcrest.Matchers; import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator; -import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender; -import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Narrative; import org.hl7.fhir.r4.model.Patient; import org.hl7.fhir.utilities.xhtml.XhtmlNode; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; import org.mockito.Mockito; -import java.util.ArrayList; -import java.util.concurrent.TimeUnit; +import java.io.IOException; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; @@ -54,20 +43,25 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; public class ResponseValidatingInterceptorR4Test { - public static IBaseResource myReturnResource; - - private static CloseableHttpClient ourClient; - private static FhirContext ourCtx = FhirContext.forR4(); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResponseValidatingInterceptorR4Test.class); + @RegisterExtension + static HttpClientExtension ourClient = new HttpClientExtension(); + private static final FhirContext ourCtx = FhirContext.forR4Cached(); + @RegisterExtension + @Order(0) + static RestfulServerExtension ourServlet = new RestfulServerExtension(ourCtx); + @RegisterExtension + @Order(1) + static ResourceProviderExtension ourProvider = new ResourceProviderExtension<>(ourServlet, new RequestValidatingInterceptorR4Test.PatientProvider()); private static int ourPort; - private static Server ourServer; - private static RestfulServer ourServlet; private ResponseValidatingInterceptor myInterceptor; @BeforeEach public void before() { - myReturnResource = null; - ourServlet.getInterceptorService().unregisterAllInterceptors(); + ourProvider.getProvider().setReturnResource(null); + ourProvider.getProvider().ourLastGraphQlQueryGet = null; + ourProvider.getProvider().ourLastGraphQlQueryPost = null; + ourServlet.unregisterAllInterceptors(); myInterceptor = new ResponseValidatingInterceptor(); // myInterceptor.setFailOnSeverity(ResultSeverityEnum.ERROR); @@ -76,15 +70,16 @@ public class ResponseValidatingInterceptorR4Test { // myInterceptor.setResponseHeaderValue(RequestValidatingInterceptor.DEFAULT_RESPONSE_HEADER_VALUE); ourServlet.registerInterceptor(myInterceptor); + ourPort = ourServlet.getPort(); } - + @SuppressWarnings("unchecked") @Test public void testInterceptorExceptionNpeNoIgnore() throws Exception { Patient patient = new Patient(); patient.addIdentifier().setValue("002"); patient.setGender(AdministrativeGender.MALE); - myReturnResource = patient; + ourProvider.getProvider().setReturnResource(patient); myInterceptor.setAddResponseHeaderOnSeverity(null); myInterceptor.setFailOnSeverity(null); @@ -94,9 +89,9 @@ public class ResponseValidatingInterceptorR4Test { myInterceptor.setIgnoreValidatorExceptions(false); Mockito.doThrow(new NullPointerException("SOME MESSAGE")).when(module).validateResource(Mockito.any(IValidationContext.class)); - + HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient?foo=bar"); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -105,7 +100,7 @@ public class ResponseValidatingInterceptorR4Test { ourLog.info("Response was:\n{}", responseContent); assertEquals(500, status.getStatusLine().getStatusCode()); - assertThat(responseContent, containsString("")); + assertThat(responseContent, containsString("\"diagnostics\": \"SOME MESSAGE\"")); } @SuppressWarnings("unchecked") @@ -114,7 +109,7 @@ public class ResponseValidatingInterceptorR4Test { Patient patient = new Patient(); patient.addIdentifier().setValue("002"); patient.setGender(AdministrativeGender.MALE); - myReturnResource = patient; + ourProvider.getProvider().setReturnResource(patient); myInterceptor.setAddResponseHeaderOnSeverity(null); myInterceptor.setFailOnSeverity(null); @@ -124,9 +119,9 @@ public class ResponseValidatingInterceptorR4Test { myInterceptor.setIgnoreValidatorExceptions(true); Mockito.doThrow(NullPointerException.class).when(module).validateResource(Mockito.any(IValidationContext.class)); - + HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient?foo=bar"); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -144,7 +139,7 @@ public class ResponseValidatingInterceptorR4Test { Patient patient = new Patient(); patient.addIdentifier().setValue("002"); patient.setGender(AdministrativeGender.MALE); - myReturnResource = patient; + ourProvider.getProvider().setReturnResource(patient); myInterceptor.setAddResponseHeaderOnSeverity(null); myInterceptor.setFailOnSeverity(null); @@ -154,9 +149,9 @@ public class ResponseValidatingInterceptorR4Test { myInterceptor.setIgnoreValidatorExceptions(false); Mockito.doThrow(new InternalErrorException("FOO")).when(module).validateResource(Mockito.any(IValidationContext.class)); - + HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient?foo=bar"); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -165,7 +160,7 @@ public class ResponseValidatingInterceptorR4Test { ourLog.info("Response was:\n{}", responseContent); assertEquals(500, status.getStatusLine().getStatusCode()); - assertThat(responseContent, containsString("")); + assertThat(responseContent, containsString("\"diagnostics\": \"FOO\"")); } @SuppressWarnings("unchecked") @@ -174,7 +169,7 @@ public class ResponseValidatingInterceptorR4Test { Patient patient = new Patient(); patient.addIdentifier().setValue("002"); patient.setGender(AdministrativeGender.MALE); - myReturnResource = patient; + ourProvider.getProvider().setReturnResource(patient); myInterceptor.setAddResponseHeaderOnSeverity(null); myInterceptor.setFailOnSeverity(null); @@ -184,9 +179,9 @@ public class ResponseValidatingInterceptorR4Test { myInterceptor.setIgnoreValidatorExceptions(true); Mockito.doThrow(InternalErrorException.class).when(module).validateResource(Mockito.any(IValidationContext.class)); - + HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient?foo=bar"); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -198,7 +193,7 @@ public class ResponseValidatingInterceptorR4Test { assertThat(status.toString(), not(containsString("X-FHIR-Response-Validation"))); } - + /** * Test for #345 */ @@ -209,7 +204,7 @@ public class ResponseValidatingInterceptorR4Test { HttpDelete httpDelete = new HttpDelete("http://localhost:" + ourPort + "/Patient/123"); - CloseableHttpResponse status = ourClient.execute(httpDelete); + CloseableHttpResponse status = ourClient.getClient().execute(httpDelete); try { ourLog.info("Response was:\n{}", status); @@ -220,6 +215,40 @@ public class ResponseValidatingInterceptorR4Test { } } + @Test + public void testGraphQlRequestResponse_GET() throws IOException { + HttpGet request = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escapeUrlParam("{name}")); + + try (CloseableHttpResponse status = ourClient.getClient().execute(request)) { + String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); + + ourLog.info("Response was:\n{}", status); + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals("{\"name\":{\"family\": \"foo\"}}", responseContent); + assertEquals("{name}", ourProvider.getProvider().ourLastGraphQlQueryGet); + } + + } + + @Test + public void testGraphQlRequestResponse_POST() throws IOException { + HttpPost request = new HttpPost("http://localhost:" + ourPort + "/Patient/123/$graphql"); + request.setEntity(new StringEntity("{\"query\": \"{name}\"}", ContentType.APPLICATION_JSON)); + + try (CloseableHttpResponse status = ourClient.getClient().execute(request)) { + String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); + + ourLog.info("Response was:\n{}", status); + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals("{\"name\":{\"family\": \"foo\"}}", responseContent); + assertEquals("{name}", ourProvider.getProvider().ourLastGraphQlQueryPost); + } + + } @Test public void testLongHeaderTruncated() throws Exception { @@ -233,12 +262,12 @@ public class ResponseValidatingInterceptorR4Test { patient.addContact().setGender(AdministrativeGender.MALE); } patient.setGender(AdministrativeGender.MALE); - myReturnResource = patient; + ourProvider.getProvider().setReturnResource(patient); HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient?foo=bar"); { - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -252,7 +281,7 @@ public class ResponseValidatingInterceptorR4Test { } { myInterceptor.setMaximumHeaderLength(100); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -273,11 +302,11 @@ public class ResponseValidatingInterceptorR4Test { patient.getText().setDiv(new XhtmlNode().setValue("
AA
")).setStatus(Narrative.NarrativeStatus.GENERATED); patient.addIdentifier().setValue("002"); patient.setGender(AdministrativeGender.MALE); - myReturnResource = patient; + ourProvider.getProvider().setReturnResource(patient); HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient?foo=bar"); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -287,23 +316,20 @@ public class ResponseValidatingInterceptorR4Test { assertEquals(200, status.getStatusLine().getStatusCode()); assertThat(status.toString(), (containsString( - "X-FHIR-Response-Validation: {\"resourceType\":\"OperationOutcome\",\"issue\":[{\"severity\":\"information\",\"code\":\"informational\",\"diagnostics\":\"No issues detected\"}]}"))); + "X-FHIR-Response-Validation: {\"resourceType\":\"OperationOutcome\",\"issue\":[{\"severity\":\"information\",\"code\":\"informational\",\"diagnostics\":\"No issues detected\"}]}"))); } - /** - * Ignored until #264 is fixed - */ @Test public void testSearchJsonInvalidNoValidatorsSpecified() throws Exception { Patient patient = new Patient(); patient.addIdentifier().setValue("002"); patient.setGender(AdministrativeGender.MALE); patient.addContact().addRelationship().setText("FOO"); - myReturnResource = patient; + ourProvider.getProvider().setReturnResource(patient); HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient?foo=bar"); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -312,7 +338,7 @@ public class ResponseValidatingInterceptorR4Test { ourLog.info("Response was:\n{}", responseContent); assertEquals(422, status.getStatusLine().getStatusCode()); - assertThat(responseContent, containsString("")); + assertThat(responseContent, containsString("\"severity\": \"error\"")); } @Test @@ -321,11 +347,11 @@ public class ResponseValidatingInterceptorR4Test { patient.getText().setDiv(new XhtmlNode().setValue("
AA
")).setStatus(Narrative.NarrativeStatus.GENERATED); patient.addIdentifier().setValue("002"); patient.setGender(AdministrativeGender.MALE); - myReturnResource = patient; + ourProvider.getProvider().setReturnResource(patient); HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient?foo=bar"); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -346,11 +372,11 @@ public class ResponseValidatingInterceptorR4Test { patient.getText().setDiv(new XhtmlNode().setValue("
AA
")).setStatus(Narrative.NarrativeStatus.GENERATED); patient.addIdentifier().setValue("002"); patient.setGender(AdministrativeGender.MALE); - myReturnResource = patient; + ourProvider.getProvider().setReturnResource(patient); HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient?foo=bar"); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -372,11 +398,11 @@ public class ResponseValidatingInterceptorR4Test { patient.addIdentifier().setValue("002"); patient.setGender(AdministrativeGender.MALE); patient.addContact().addRelationship().setText("FOO"); - myReturnResource = patient; + ourProvider.getProvider().setReturnResource(patient); HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient?foo=bar"); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -397,11 +423,11 @@ public class ResponseValidatingInterceptorR4Test { patient.addIdentifier().setValue("002"); patient.setGender(AdministrativeGender.MALE); patient.addContact().addRelationship().setText("FOO"); - myReturnResource = patient; + ourProvider.getProvider().setReturnResource(patient); HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient?foo=bar"); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -410,7 +436,7 @@ public class ResponseValidatingInterceptorR4Test { ourLog.info("Response was:\n{}", responseContent); assertEquals(422, status.getStatusLine().getStatusCode()); - assertThat(responseContent, Matchers.containsString("")); + assertThat(responseContent, Matchers.containsString("\"severity\": \"error\"")); } @Test @@ -419,11 +445,11 @@ public class ResponseValidatingInterceptorR4Test { patient.getText().setDiv(new XhtmlNode().setValue("
AA
")).setStatus(Narrative.NarrativeStatus.GENERATED); patient.addIdentifier().setValue("002"); patient.setGender(AdministrativeGender.MALE); - myReturnResource = patient; + ourProvider.getProvider().setReturnResource(patient); HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/Patient?foo=bar"); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -443,7 +469,7 @@ public class ResponseValidatingInterceptorR4Test { myInterceptor.setResponseHeaderValueNoIssues("No issues"); HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/metadata"); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); IOUtils.closeQuietly(status.getEntity().getContent()); @@ -463,7 +489,7 @@ public class ResponseValidatingInterceptorR4Test { myInterceptor.setAddResponseHeaderOnSeverity(ResultSeverityEnum.INFORMATION); HttpGet httpPost = new HttpGet("http://localhost:" + ourPort + "/metadata?_pretty=true"); - HttpResponse status = ourClient.execute(httpPost); + HttpResponse status = ourClient.getClient().execute(httpPost); String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8); ourLog.info(responseContent); @@ -476,56 +502,4 @@ public class ResponseValidatingInterceptorR4Test { assertThat(status.toString(), (containsString("X-FHIR-Response-Validation"))); } - @AfterAll - public static void afterClassClearContext() throws Exception { - JettyUtil.closeServer(ourServer); - TestUtil.randomizeLocaleAndTimezone(); - } - - @BeforeAll - public static void beforeClass() throws Exception { - ourServer = new Server(0); - - PatientProvider patientProvider = new PatientProvider(); - - ServletHandler proxyHandler = new ServletHandler(); - ourServlet = new RestfulServer(ourCtx); - ourServlet.setResourceProviders(patientProvider); - ourServlet.setDefaultResponseEncoding(EncodingEnum.XML); - - ServletHolder servletHolder = new ServletHolder(ourServlet); - proxyHandler.addServletWithMapping(servletHolder, "/*"); - ourServer.setHandler(proxyHandler); - JettyUtil.startServer(ourServer); - ourPort = JettyUtil.getPortForStartedServer(ourServer); - - PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); - HttpClientBuilder builder = HttpClientBuilder.create(); - builder.setConnectionManager(connectionManager); - ourClient = builder.build(); - - } - - public static class PatientProvider implements IResourceProvider { - - @Delete - public MethodOutcome delete(@IdParam IdType theId) { - return new MethodOutcome(theId.withVersion("2")); - } - - @Override - public Class getResourceType() { - return Patient.class; - } - - @Search - public ArrayList search(@OptionalParam(name = "foo") StringParam theString) { - ArrayList retVal = new ArrayList<>(); - myReturnResource.setId("1"); - retVal.add(myReturnResource); - return retVal; - } - - } - }