Fix #1163 - Correctly handle invalid CapabilityStatement

This commit is contained in:
James Agnew 2019-01-11 08:01:20 -07:00
parent dec53c1eea
commit fc09ed6966
3 changed files with 1164 additions and 1134 deletions

View File

@ -301,7 +301,7 @@ public abstract class RestfulClientFactory implements IRestfulClientFactory {
conformance = (IBaseResource) client.fetchConformance().ofType(implementingClass).execute(); conformance = (IBaseResource) client.fetchConformance().ofType(implementingClass).execute();
} catch (FhirClientConnectionException e) { } catch (FhirClientConnectionException e) {
if (!myContext.getVersion().getVersion().isOlderThan(FhirVersionEnum.DSTU3) && e.getCause() instanceof DataFormatException) { if (!myContext.getVersion().getVersion().isOlderThan(FhirVersionEnum.DSTU3) && e.getCause() instanceof DataFormatException) {
capabilityStatementResourceName = "Conformance"; capabilityStatementResourceName = "CapabilityStatement";
implementingClass = myContext.getResourceDefinition(capabilityStatementResourceName).getImplementingClass(); implementingClass = myContext.getResourceDefinition(capabilityStatementResourceName).getImplementingClass();
conformance = (IBaseResource) client.fetchConformance().ofType(implementingClass).execute(); conformance = (IBaseResource) client.fetchConformance().ofType(implementingClass).execute();
} else { } else {

View File

@ -10,7 +10,9 @@ import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.SummaryEnum; import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.apache.ApacheHttpRequest; import ca.uhn.fhir.rest.client.apache.ApacheHttpRequest;
import ca.uhn.fhir.rest.client.api.IBasicClient; import ca.uhn.fhir.rest.client.api.IBasicClient;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor; import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor;
import ca.uhn.fhir.rest.param.*; import ca.uhn.fhir.rest.param.*;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
@ -57,8 +59,8 @@ import static org.mockito.Mockito.when;
public class ClientR4Test { public class ClientR4Test {
private static FhirContext ourCtx = FhirContext.forR4();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ClientR4Test.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ClientR4Test.class);
private static FhirContext ourCtx = FhirContext.forR4();
private HttpClient myHttpClient; private HttpClient myHttpClient;
private HttpResponse myHttpResponse; private HttpResponse myHttpResponse;
@ -959,7 +961,6 @@ public class ClientR4Test {
} }
@Test @Test
public void testSearchWithStringIncludes() throws Exception { public void testSearchWithStringIncludes() throws Exception {
@ -1142,6 +1143,29 @@ public class ClientR4Test {
assertNull(response.getResource()); assertNull(response.getResource());
} }
@Test
public void testValidateServerBaseWithInvalidResponse() throws Exception {
String response = "AAAAAAA";
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(response), Charset.forName("UTF-8")));
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE);
IGenericClient client = ourCtx.newRestfulGenericClient("http://testValidateServerBaseWithInvalidResponse");
try {
client.read().resource("Patient").withId("1").execute();
fail();
} catch (FhirClientConnectionException e) {
assertEquals("Failed to retrieve the server metadata statement during client initialization. URL used was http://testValidateServerBaseWithInvalidResponse/metadata", e.getMessage());
}
}
@Test @Test
public void testValidateOutcomeResponse() throws Exception { public void testValidateOutcomeResponse() throws Exception {
@ -1221,6 +1245,51 @@ public class ClientR4Test {
} }
} }
private interface ClientWithoutAnnotation extends IBasicClient {
Patient read(@IdParam IdType theId);
}
public interface ITestClientWithCustomType extends IBasicClient {
@Search()
public CustomPatient getPatientByDob(@RequiredParam(name = Patient.SP_BIRTHDATE) DateParam theBirthDate);
}
public interface ITestClientWithCustomTypeList extends IBasicClient {
@Search()
public List<CustomPatient> getPatientByDob(@RequiredParam(name = Patient.SP_BIRTHDATE) DateParam theBirthDate);
}
public interface ITestClientWithElements extends IBasicClient {
@Search()
public List<Patient> getPatientWithIncludes(@Elements Set<String> theElements);
@Search()
public List<Patient> getPatientWithIncludes(@Elements String theElements);
}
public interface ITestClientWithStringIncludes extends IBasicClient {
@Search()
public Patient getPatientWithIncludes(@RequiredParam(name = "withIncludes") StringParam theString, @IncludeParam String theInclude);
}
public interface ITestClientWithSummary extends IBasicClient {
@Search()
public List<Patient> getPatientWithIncludes(List<SummaryEnum> theSummary);
@Search()
public List<Patient> getPatientWithIncludes(SummaryEnum theSummary);
}
@ResourceDef(name = "Patient")
public static class CustomPatient extends Patient {
private static final long serialVersionUID = 1L;
// nothing
}
@AfterClass @AfterClass
public static void afterClassClearContext() { public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest(); TestUtil.clearAllStaticFieldsForUnitTest();
@ -1265,49 +1334,4 @@ public class ClientR4Test {
// return msg; // return msg;
} }
private interface ClientWithoutAnnotation extends IBasicClient {
Patient read(@IdParam IdType theId);
}
@ResourceDef(name = "Patient")
public static class CustomPatient extends Patient {
private static final long serialVersionUID = 1L;
// nothing
}
public interface ITestClientWithCustomType extends IBasicClient {
@Search()
public CustomPatient getPatientByDob(@RequiredParam(name = Patient.SP_BIRTHDATE) DateParam theBirthDate);
}
public interface ITestClientWithCustomTypeList extends IBasicClient {
@Search()
public List<CustomPatient> getPatientByDob(@RequiredParam(name = Patient.SP_BIRTHDATE) DateParam theBirthDate);
}
public interface ITestClientWithElements extends IBasicClient {
@Search()
public List<Patient> getPatientWithIncludes(@Elements Set<String> theElements);
@Search()
public List<Patient> getPatientWithIncludes(@Elements String theElements);
}
public interface ITestClientWithStringIncludes extends IBasicClient {
@Search()
public Patient getPatientWithIncludes(@RequiredParam(name = "withIncludes") StringParam theString, @IncludeParam String theInclude);
}
public interface ITestClientWithSummary extends IBasicClient {
@Search()
public List<Patient> getPatientWithIncludes(List<SummaryEnum> theSummary);
@Search()
public List<Patient> getPatientWithIncludes(SummaryEnum theSummary);
}
} }

View File

@ -283,6 +283,12 @@
AuthorizationInterceptor could not authorize these requests if it was depending on AuthorizationInterceptor could not authorize these requests if it was depending on
headers being present. headers being present.
</action> </action>
<action type="fix">
When using a client in DSTU3/R4 mode, if the client attempted to validate the server
CapabilityStatement but was not able to parse the response, the client would throw
an exception with a misleading error about the Conformance resource not existing. This
has been corrected. Thanks to Shayaan Munshi for reporting and providing a test case!
</action>
</release> </release>
<release version="3.6.0" date="2018-11-12" description="Food"> <release version="3.6.0" date="2018-11-12" description="Food">
<action type="add"> <action type="add">