@Test
  public void testServerReturnsWrongVersionForDstu2() throws Exception {
    Conformance conf = new Conformance();
    conf.setFhirVersion("0.80");
    String msg = myCtx.newXmlParser().encodeResourceToString(conf);

    ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);

    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")));

    when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);

    myCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE);
    try {
      myCtx.newRestfulGenericClient("http://foo").read(new UriDt("http://foo/Patient/123"));
      fail();
    } catch (FhirClientInappropriateForServerException e) {
      String out = e.toString();
      String want =
          "The server at base URL \"http://foo/metadata\" returned a conformance statement indicating that it supports FHIR version \"0.80\" which corresponds to DSTU1, but this client is configured to use DSTU2 (via the FhirContext)";
      ourLog.info(out);
      ourLog.info(want);
      assertThat(out, containsString(want));
    }
  }
  @Test
  public void testForceConformanceCheck() throws Exception {
    Conformance conf = new Conformance();
    conf.setFhirVersion("0.5.0");
    final String confResource = myCtx.newXmlParser().encodeResourceToString(conf);

    ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);

    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())
        .thenAnswer(
            new Answer<InputStream>() {
              @Override
              public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
                if (myFirstResponse) {
                  myFirstResponse = false;
                  return new ReaderInputStream(
                      new StringReader(confResource), Charset.forName("UTF-8"));
                } else {
                  Patient resource = new Patient();
                  resource.addName().addFamily().setValue("FAM");
                  return new ReaderInputStream(
                      new StringReader(myCtx.newXmlParser().encodeResourceToString(resource)),
                      Charset.forName("UTF-8"));
                }
              }
            });

    when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);

    myCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE);

    IGenericClient client = myCtx.newRestfulGenericClient("http://foo");
    client.registerInterceptor(new BasicAuthInterceptor("USER", "PASS"));

    client.forceConformanceCheck();

    assertEquals(1, capt.getAllValues().size());

    Patient pt = (Patient) client.read(new UriDt("http://foo/Patient/123"));
    assertEquals("FAM", pt.getNameFirstRep().getFamilyAsSingleString());

    assertEquals(2, capt.getAllValues().size());

    Header auth = capt.getAllValues().get(0).getFirstHeader("Authorization");
    assertNotNull(auth);
    assertEquals("Basic VVNFUjpQQVNT", auth.getValue());
    auth = capt.getAllValues().get(1).getFirstHeader("Authorization");
    assertNotNull(auth);
    assertEquals("Basic VVNFUjpQQVNT", auth.getValue());
  }
  @Test
  public void testServerReturnsAppropriateVersionForDstu2_050() throws Exception {
    Conformance conf = new Conformance();
    conf.setFhirVersion("0.5.0");
    final String confResource = myCtx.newXmlParser().encodeResourceToString(conf);

    ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);

    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())
        .thenAnswer(
            new Answer<InputStream>() {
              @Override
              public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
                if (myFirstResponse) {
                  myFirstResponse = false;
                  return new ReaderInputStream(
                      new StringReader(confResource), Charset.forName("UTF-8"));
                } else {
                  return new ReaderInputStream(
                      new StringReader(myCtx.newXmlParser().encodeResourceToString(new Patient())),
                      Charset.forName("UTF-8"));
                }
              }
            });

    when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);

    myCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE);
    IGenericClient client = myCtx.newRestfulGenericClient("http://foo");

    // don't load the conformance until the first time the client is actually used
    assertTrue(myFirstResponse);
    client.read(new UriDt("http://foo/Patient/123"));
    assertFalse(myFirstResponse);
    myCtx.newRestfulGenericClient("http://foo").read(new UriDt("http://foo/Patient/123"));
    myCtx.newRestfulGenericClient("http://foo").read(new UriDt("http://foo/Patient/123"));

    // Conformance only loaded once, then 3 reads
    verify(myHttpClient, times(4)).execute(Matchers.any(HttpUriRequest.class));
  }
  private IResource loadAndAddConfDstu2(
      HttpServletRequest theServletRequest, final HomeRequest theRequest, final ModelMap theModel) {
    CaptureInterceptor interceptor = new CaptureInterceptor();
    GenericClient client =
        theRequest.newClient(theServletRequest, getContext(theRequest), myConfig, interceptor);

    ca.uhn.fhir.model.dstu2.resource.Conformance conformance;
    try {
      conformance = (ca.uhn.fhir.model.dstu2.resource.Conformance) client.conformance();
    } catch (Exception e) {
      ourLog.warn("Failed to load conformance statement", e);
      theModel.put("errorMsg", "Failed to load conformance statement, error was: " + e.toString());
      conformance = new ca.uhn.fhir.model.dstu2.resource.Conformance();
    }

    theModel.put(
        "jsonEncodedConf",
        getContext(theRequest).newJsonParser().encodeResourceToString(conformance));

    Map<String, Number> resourceCounts = new HashMap<String, Number>();
    long total = 0;
    for (ca.uhn.fhir.model.dstu2.resource.Conformance.Rest nextRest : conformance.getRest()) {
      for (ca.uhn.fhir.model.dstu2.resource.Conformance.RestResource nextResource :
          nextRest.getResource()) {
        List<ExtensionDt> exts = nextResource.getUndeclaredExtensionsByUrl(RESOURCE_COUNT_EXT_URL);
        if (exts != null && exts.size() > 0) {
          Number nextCount = ((DecimalDt) (exts.get(0).getValue())).getValueAsNumber();
          resourceCounts.put(nextResource.getTypeElement().getValue(), nextCount);
          total += nextCount.longValue();
        }
      }
    }
    theModel.put("resourceCounts", resourceCounts);

    if (total > 0) {
      for (ca.uhn.fhir.model.dstu2.resource.Conformance.Rest nextRest : conformance.getRest()) {
        Collections.sort(
            nextRest.getResource(),
            new Comparator<ca.uhn.fhir.model.dstu2.resource.Conformance.RestResource>() {
              @Override
              public int compare(
                  ca.uhn.fhir.model.dstu2.resource.Conformance.RestResource theO1,
                  ca.uhn.fhir.model.dstu2.resource.Conformance.RestResource theO2) {
                DecimalDt count1 = new DecimalDt();
                List<ExtensionDt> count1exts =
                    theO1.getUndeclaredExtensionsByUrl(RESOURCE_COUNT_EXT_URL);
                if (count1exts != null && count1exts.size() > 0) {
                  count1 = (DecimalDt) count1exts.get(0).getValue();
                }
                DecimalDt count2 = new DecimalDt();
                List<ExtensionDt> count2exts =
                    theO2.getUndeclaredExtensionsByUrl(RESOURCE_COUNT_EXT_URL);
                if (count2exts != null && count2exts.size() > 0) {
                  count2 = (DecimalDt) count2exts.get(0).getValue();
                }
                int retVal = count2.compareTo(count1);
                if (retVal == 0) {
                  retVal =
                      theO1
                          .getTypeElement()
                          .getValue()
                          .compareTo(theO2.getTypeElement().getValue());
                }
                return retVal;
              }
            });
      }
    }

    theModel.put("conf", conformance);
    theModel.put("requiredParamExtension", ExtensionConstants.PARAM_IS_REQUIRED);

    return conformance;
  }