package ca.uhn.fhir.rest.client; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.io.StringReader; import java.nio.charset.Charset; import org.apache.commons.io.input.ReaderInputStream; import org.apache.http.Header; 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.hl7.fhir.instance.model.Patient; 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.api.ResourceMetadataKeyEnum; import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.exceptions.NotModifiedException; import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException; /** * Created by dsotnikov on 2/25/2014. */ public class ETagClientTest { private static FhirContext ourCtx; private HttpClient myHttpClient; private HttpResponse myHttpResponse; @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()); } private String getResourceResult() { //@formatter:off String msg = "<Patient xmlns=\"http://hl7.org/fhir\">" + "<id value=\"123\"/>" + "<meta>" + "<versionId value=\"4444\"/>" + "</meta>" + "<text><status value=\"generated\" /><div xmlns=\"http://www.w3.org/1999/xhtml\">John Cardinal: 444333333 </div></text>" + "<identifier><label value=\"SSN\" /><system value=\"http://orionhealth.com/mrn\" /><value value=\"PRP1660\" /></identifier>" + "<name><use value=\"official\" /><family value=\"Cardinal\" /><given value=\"John\" /></name>" + "<name><family value=\"Kramer\" /><given value=\"Doe\" /></name>" + "<telecom><system value=\"phone\" /><value value=\"555-555-2004\" /><use value=\"work\" /></telecom>" + "<gender value=\"male\"/>" + "<address><use value=\"home\" /><line value=\"2222 Home Street\" /></address><active value=\"true\" />" + "</Patient>"; //@formatter:on return msg; } private Patient getResource() { return ourCtx.newXmlParser().parseResource(Patient.class, getResourceResult()); } @Test public void testReadWithContentLocationInResponse() throws Exception { String msg = getResourceResult(); 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), 200, "OK")); when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); //@formatter:off Header[] headers = new Header[] { new BasicHeader(Constants.HEADER_CONTENT_LOCATION, "http://foo.com/Patient/123/_history/2333"), new BasicHeader(Constants.HEADER_ETAG, "\"9999\"") }; //@formatter:on when(myHttpResponse.getAllHeaders()).thenReturn(headers); IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir"); Patient response = client.read(Patient.class, new IdDt("Patient/1234")); assertEquals("http://foo.com/Patient/123/_history/2333", response.getIdElement().getValue()); } @Test public void testReadWithIfNoneMatch() throws Exception { 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), Constants.STATUS_HTTP_304_NOT_MODIFIED, "Not modified")); when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir"); int count = 0; //@formatter:off when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""))); try { client .read() .resource(Patient.class) .withId(new IdDt("Patient/1234")) .execute(); fail(); } catch (NotModifiedException e) { // good! } //@formatter:on assertEquals("http://example.com/fhir/Patient/1234", capt.getAllValues().get(count).getURI().toString()); count++; //@formatter:off when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""))); Patient expected = new Patient(); Patient response = client .read() .resource(Patient.class) .withId(new IdDt("Patient/1234")) .ifVersionMatches("9876").returnResource(expected) .execute(); //@formatter:on assertSame(expected, response); assertEquals("http://example.com/fhir/Patient/1234", capt.getAllValues().get(count).getURI().toString()); assertEquals("\"9876\"", capt.getAllValues().get(count).getHeaders(Constants.HEADER_IF_NONE_MATCH_LC)[0].getValue()); count++; } @Test public void testUpdateWithIfMatch() throws Exception { 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), Constants.STATUS_HTTP_200_OK, "OK")); when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir"); int count = 0; //@formatter:off when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""))); client .update() .resource(getResource()) .withId(new IdDt("Patient/1234")) .execute(); //@formatter:on assertEquals("http://example.com/fhir/Patient/1234", capt.getAllValues().get(count).getURI().toString()); assertEquals(0, capt.getAllValues().get(count).getHeaders(Constants.HEADER_IF_MATCH_LC).length); count++; //@formatter:off when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""))); client .update() .resource(getResource()) .withId(new IdDt("Patient/1234/_history/9876")) .execute(); //@formatter:on assertEquals("http://example.com/fhir/Patient/1234", capt.getAllValues().get(count).getURI().toString()); assertEquals("\"9876\"", capt.getAllValues().get(count).getHeaders(Constants.HEADER_IF_MATCH_LC)[0].getValue()); count++; } @Test public void testUpdateWithIfMatchWithPreconditionFailed() throws Exception { 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), Constants.STATUS_HTTP_412_PRECONDITION_FAILED, "Precondition Failed")); when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir"); int count = 0; //@formatter:off when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""))); try { client .update() .resource(getResource()) .withId(new IdDt("Patient/1234/_history/9876")) .execute(); fail(); } catch (PreconditionFailedException e) { // good } //@formatter:on assertEquals("http://example.com/fhir/Patient/1234", capt.getAllValues().get(count).getURI().toString()); assertEquals("\"9876\"", capt.getAllValues().get(count).getHeaders(Constants.HEADER_IF_MATCH_LC)[0].getValue()); count++; //@formatter:off when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""))); try { Patient resource = getResource(); resource.setId(new IdDt("Patient/1234/_history/9876")); client .update() .resource(resource) .execute(); fail(); } catch (PreconditionFailedException e) { // good } //@formatter:on assertEquals("http://example.com/fhir/Patient/1234", capt.getAllValues().get(count).getURI().toString()); assertEquals("\"9876\"", capt.getAllValues().get(count).getHeaders(Constants.HEADER_IF_MATCH_LC)[0].getValue()); count++; } @Test public void testReadWithETag() throws Exception { String msg = getResourceResult(); 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), 200, "OK")); when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); Header[] headers = new Header[] { new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08 GMT"), new BasicHeader(Constants.HEADER_CONTENT_LOCATION, "http://foo.com/Patient/123/_history/2333"), new BasicHeader(Constants.HEADER_CATEGORY, "http://foo/tagdefinition.html; scheme=\"http://hl7.org/fhir/tag\"; label=\"Some tag\"") }; when(myHttpResponse.getAllHeaders()).thenReturn(headers); IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir"); int count = 0; Patient response = client.read().resource(Patient.class).withId(new IdDt("Patient/1234")).execute(); assertThat(response.getName().get(0).getFamily().get(0).getValue(), StringContains.containsString("Cardinal")); assertEquals("http://example.com/fhir/Patient/1234", capt.getAllValues().get(count++).getURI().toString()); when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); response = (Patient) client.read().resource("Patient").withId("1234").execute(); assertThat(response.getName().get(0).getFamily().get(0).getValue(), StringContains.containsString("Cardinal")); assertEquals("http://example.com/fhir/Patient/1234", capt.getAllValues().get(count++).getURI().toString()); when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); response = client.read().resource(Patient.class).withIdAndVersion("1234", "22").execute(); assertThat(response.getName().get(0).getFamily().get(0).getValue(), StringContains.containsString("Cardinal")); assertEquals("http://example.com/fhir/Patient/1234/_history/22", capt.getAllValues().get(count++).getURI().toString()); when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); response = client.read().resource(Patient.class).withUrl("http://foo/Patient/22").execute(); assertThat(response.getName().get(0).getFamily().get(0).getValue(), StringContains.containsString("Cardinal")); assertEquals("http://foo/Patient/22", capt.getAllValues().get(count++).getURI().toString()); } @BeforeClass public static void beforeClass() { ourCtx = FhirContext.forDstu2Hl7Org(); } }