Fix #1763 - Include bundle type in summary=count responses (#1773)

* Fix #1763 - Include bundle type in summary=count responses

* Test fix
This commit is contained in:
James Agnew 2020-03-24 16:24:41 -04:00 committed by GitHub
parent c6d23a8bc6
commit eaaddaf7ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 30 deletions

View File

@ -0,0 +1,5 @@
---
type: fix
issue: 1763
title: In servers, when requesting _summary=count, the response Bundle.type value was filtered, leading
to an invalid response bundle. This has been corrected. Thanks to GitHub user @Legi429 for reporting!

View File

@ -45,6 +45,7 @@ import ca.uhn.fhir.rest.server.method.SummaryEnumParameter;
import ca.uhn.fhir.util.BinaryUtil; import ca.uhn.fhir.util.BinaryUtil;
import ca.uhn.fhir.util.DateUtils; import ca.uhn.fhir.util.DateUtils;
import ca.uhn.fhir.util.UrlUtil; import ca.uhn.fhir.util.UrlUtil;
import com.google.common.collect.Sets;
import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseBinary; import org.hl7.fhir.instance.model.api.IBaseBinary;
import org.hl7.fhir.instance.model.api.IBaseReference; import org.hl7.fhir.instance.model.api.IBaseReference;
@ -163,7 +164,7 @@ public class RestfulServerUtils {
} }
if (summaryModeCount) { if (summaryModeCount) {
parser.setEncodeElements(Collections.singleton("Bundle.total")); parser.setEncodeElements(Sets.newHashSet("Bundle.total", "Bundle.type"));
} else if (summaryMode.contains(SummaryEnum.TEXT) && summaryMode.size() == 1) { } else if (summaryMode.contains(SummaryEnum.TEXT) && summaryMode.size() == 1) {
parser.setEncodeElements(TEXT_ENCODE_ELEMENTS); parser.setEncodeElements(TEXT_ENCODE_ELEMENTS);
parser.setEncodeElementsAppliesToChildResourcesOnly(true); parser.setEncodeElementsAppliesToChildResourcesOnly(true);

View File

@ -10,6 +10,7 @@ import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum; import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.SearchStyleEnum; import ca.uhn.fhir.rest.api.SearchStyleEnum;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.gclient.StringClientParam; import ca.uhn.fhir.rest.gclient.StringClientParam;
@ -21,7 +22,6 @@ import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ValidationResult; import ca.uhn.fhir.validation.ValidationResult;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
@ -66,7 +66,16 @@ public class SearchR4Test {
ourIdentifiers = null; ourIdentifiers = null;
} }
private Bundle executeAndReturnLinkNext(HttpGet httpGet, EncodingEnum theExpectEncoding) throws IOException, ClientProtocolException { private Bundle executeSearchAndValidateHasLinkNext(HttpGet httpGet, EncodingEnum theExpectEncoding) throws IOException {
Bundle bundle = executeSearch(httpGet, theExpectEncoding);
String linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertNotNull(linkNext);
assertEquals(10, bundle.getEntry().size());
return bundle;
}
private Bundle executeSearch(HttpGet httpGet, EncodingEnum theExpectEncoding) throws IOException {
Bundle bundle; Bundle bundle;
try (CloseableHttpResponse status = ourClient.execute(httpGet)) { try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
@ -76,9 +85,6 @@ public class SearchR4Test {
assertEquals(theExpectEncoding, ct); assertEquals(theExpectEncoding, ct);
bundle = ct.newParser(ourCtx).parseResource(Bundle.class, responseContent); bundle = ct.newParser(ourCtx).parseResource(Bundle.class, responseContent);
validate(bundle); validate(bundle);
assertEquals(10, bundle.getEntry().size());
String linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertNotNull(linkNext);
} }
return bundle; return bundle;
} }
@ -98,6 +104,21 @@ public class SearchR4Test {
} }
/**
* See #1763
*/
@Test
public void testSummaryCount() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&"+Constants.PARAM_SUMMARY + "=" + SummaryEnum.COUNT.getCode());
Bundle bundle = executeSearch(httpGet, EncodingEnum.JSON);
ourLog.info(toJson(bundle));
assertEquals(200, bundle.getTotal());
assertEquals("searchset", bundle.getType().toCode());
assertEquals(0, bundle.getEntry().size());
}
@Test @Test
public void testPagingPreservesElements() throws Exception { public void testPagingPreservesElements() throws Exception {
HttpGet httpGet; HttpGet httpGet;
@ -107,7 +128,7 @@ public class SearchR4Test {
// Initial search // Initial search
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_elements=name&_elements:exclude=birthDate,active"); httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_elements=name&_elements:exclude=birthDate,active");
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.JSON);
assertThat(toJson(bundle), not(containsString("\"active\""))); assertThat(toJson(bundle), not(containsString("\"active\"")));
linkSelf = bundle.getLink(Constants.LINK_SELF).getUrl(); linkSelf = bundle.getLink(Constants.LINK_SELF).getUrl();
assertThat(linkSelf, containsString("_elements=name")); assertThat(linkSelf, containsString("_elements=name"));
@ -118,7 +139,7 @@ public class SearchR4Test {
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.JSON);
assertThat(toJson(bundle), not(containsString("\"active\""))); assertThat(toJson(bundle), not(containsString("\"active\"")));
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_elements=name")); assertThat(linkNext, containsString("_elements=name"));
@ -126,7 +147,7 @@ public class SearchR4Test {
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.JSON);
assertThat(toJson(bundle), not(containsString("\"active\""))); assertThat(toJson(bundle), not(containsString("\"active\"")));
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_elements=name")); assertThat(linkNext, containsString("_elements=name"));
@ -134,7 +155,7 @@ public class SearchR4Test {
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.JSON);
assertThat(toJson(bundle), not(containsString("\"active\""))); assertThat(toJson(bundle), not(containsString("\"active\"")));
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_elements=name")); assertThat(linkNext, containsString("_elements=name"));
@ -203,25 +224,25 @@ public class SearchR4Test {
// Initial search // Initial search
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_format=" + Constants.CT_FHIR_JSON_NEW); httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_format=" + Constants.CT_FHIR_JSON_NEW);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW))); assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW))); assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW))); assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW))); assertThat(linkNext, containsString("_format=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_JSON_NEW)));
@ -235,26 +256,26 @@ public class SearchR4Test {
// Initial search // Initial search
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_format=json"); httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_format=json");
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.JSON);
assertThat(toJson(bundle), containsString("active")); assertThat(toJson(bundle), containsString("active"));
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_format=json")); assertThat(linkNext, containsString("_format=json"));
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_format=json")); assertThat(linkNext, containsString("_format=json"));
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_format=json")); assertThat(linkNext, containsString("_format=json"));
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_format=json")); assertThat(linkNext, containsString("_format=json"));
@ -268,25 +289,25 @@ public class SearchR4Test {
// Initial search // Initial search
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar"); httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar");
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, not(containsString("_format"))); assertThat(linkNext, not(containsString("_format")));
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, not(containsString("_format"))); assertThat(linkNext, not(containsString("_format")));
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, not(containsString("_format"))); assertThat(linkNext, not(containsString("_format")));
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.JSON);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, not(containsString("_format"))); assertThat(linkNext, not(containsString("_format")));
@ -301,28 +322,28 @@ public class SearchR4Test {
// Initial search // Initial search
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar"); httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar");
httpGet.addHeader(Constants.HEADER_ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"); httpGet.addHeader(Constants.HEADER_ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.XML);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, not(containsString("_format"))); assertThat(linkNext, not(containsString("_format")));
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
httpGet.addHeader(Constants.HEADER_ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"); httpGet.addHeader(Constants.HEADER_ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.XML);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, not(containsString("_format"))); assertThat(linkNext, not(containsString("_format")));
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
httpGet.addHeader(Constants.HEADER_ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"); httpGet.addHeader(Constants.HEADER_ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.XML);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, not(containsString("_format"))); assertThat(linkNext, not(containsString("_format")));
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
httpGet.addHeader(Constants.HEADER_ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"); httpGet.addHeader(Constants.HEADER_ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.XML);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, not(containsString("_format"))); assertThat(linkNext, not(containsString("_format")));
@ -336,25 +357,25 @@ public class SearchR4Test {
// Initial search // Initial search
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_format=xml"); httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_format=xml");
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.XML);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_format=xml")); assertThat(linkNext, containsString("_format=xml"));
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.XML);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_format=xml")); assertThat(linkNext, containsString("_format=xml"));
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.XML);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_format=xml")); assertThat(linkNext, containsString("_format=xml"));
// Fetch the next page // Fetch the next page
httpGet = new HttpGet(linkNext); httpGet = new HttpGet(linkNext);
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML); bundle = executeSearchAndValidateHasLinkNext(httpGet, EncodingEnum.XML);
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl(); linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
assertThat(linkNext, containsString("_format=xml")); assertThat(linkNext, containsString("_format=xml"));