package ca.uhn.fhir.rest.client; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import java.io.StringReader; import java.nio.charset.Charset; import org.apache.commons.io.input.ReaderInputStream; import org.apache.http.HttpResponse; import org.apache.http.ProtocolVersion; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicStatusLine; import org.hamcrest.core.StringContains; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.model.base.resource.BaseOperationOutcome; import ca.uhn.fhir.model.dstu.resource.OperationOutcome; import ca.uhn.fhir.model.dstu.resource.Patient; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.Read; import ca.uhn.fhir.rest.client.api.IRestfulClient; import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.util.TestUtil; public class ExceptionHandlingTest { private static FhirContext ourCtx; private HttpClient myHttpClient; private HttpResponse myHttpResponse; @BeforeClass public static void beforeClass() { ourCtx = FhirContext.forDstu1(); } @Before public void before() { myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs()); ourCtx.getRestfulClientFactory().setHttpClient(myHttpClient); ourCtx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.NEVER); myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs()); } @Test public void testFail500WithPlainMessage() throws Exception { String msg = "Help I'm a bug"; String contentType = Constants.CT_TEXT; ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 500, "Internal Error")); when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", contentType + "; charset=UTF-8")); when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir"); try { client.read(Patient.class, new IdDt("Patient/1234")); fail(); } catch (InternalErrorException e) { assertThat(e.getMessage(), StringContains.containsString("HTTP 500 Internal Error")); assertThat(e.getMessage(), StringContains.containsString("Help I'm a bug")); } } @Test public void testFail500WithOperationOutcomeMessage() throws Exception { OperationOutcome oo = new OperationOutcome(); oo.getIssueFirstRep().getDetails().setValue("Help I'm a bug"); String msg = ourCtx.newXmlParser().encodeResourceToString(oo); String contentType = Constants.CT_FHIR_XML; ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 500, "Internal Error")); when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", contentType + "; charset=UTF-8")); when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir"); try { client.read(Patient.class, new IdDt("Patient/1234")); fail(); } catch (InternalErrorException e) { assertThat(e.getMessage(), StringContains.containsString("HTTP 500 Internal Error")); assertThat(e.getMessage(), StringContains.containsString("Help I'm a bug")); } } @Test public void testFail500WithUnexpectedResource() throws Exception { Patient patient = new Patient(); patient.addIdentifier().setSystem("foo").setValue("bar"); String msg = ourCtx.newXmlParser().encodeResourceToString(patient); String contentType = Constants.CT_FHIR_XML; ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 500, "Internal Error")); when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", contentType + "; charset=UTF-8")); when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir"); try { client.read(Patient.class, new IdDt("Patient/1234")); fail(); } catch (InternalErrorException e) { assertEquals("HTTP 500 Internal Error", e.getMessage()); assertThat(e.getResponseBody(), StringContains.containsString("value=\"foo\"")); } } @Test public void testFail500WithOperationOutcomeMessageJson() throws Exception { OperationOutcome oo = new OperationOutcome(); oo.getIssueFirstRep().getDetails().setValue("Help I'm a bug"); String msg = ourCtx.newJsonParser().encodeResourceToString(oo); String contentType = Constants.CT_FHIR_JSON; ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 500, "Internal Error")); when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", contentType + "; charset=UTF-8")); when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir"); try { client.read(Patient.class, new IdDt("Patient/1234")); fail(); } catch (InternalErrorException e) { assertThat(e.getMessage(), StringContains.containsString("HTTP 500 Internal Error")); assertThat(e.getMessage(), StringContains.containsString("Help I'm a bug")); assertNotNull(e.getOperationOutcome()); assertEquals("Help I'm a bug", ((BaseOperationOutcome) e.getOperationOutcome()).getIssueFirstRep().getDetailsElement().getValue()); } } @Test public void testFail500WithOperationOutcomeMessageGeneric() throws Exception { OperationOutcome oo = new OperationOutcome(); oo.getIssueFirstRep().getDetails().setValue("Help I'm a bug"); String msg = ourCtx.newJsonParser().encodeResourceToString(oo); String contentType = Constants.CT_FHIR_JSON; ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 500, "Internal Error")); when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", contentType + "; charset=UTF-8")); when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); IMyClient client = ourCtx.newRestfulClient(IMyClient.class, "http://example.com/fhir"); try { client.read(new IdDt("Patient/1234")); fail(); } catch (InternalErrorException e) { assertThat(e.getMessage(), StringContains.containsString("HTTP 500 Internal Error")); assertThat(e.getMessage(), StringContains.containsString("Help I'm a bug")); assertNotNull(e.getOperationOutcome()); assertEquals("Help I'm a bug", ((BaseOperationOutcome) e.getOperationOutcome()).getIssueFirstRep().getDetailsElement().getValue()); } } public interface IMyClient extends IRestfulClient { @Read Patient read(@IdParam IdDt theId); } @AfterClass public static void afterClassClearContext() { TestUtil.clearAllStaticFieldsForUnitTest(); } }