Ejemplo n.º 1
0
public class ModelExtensionTest {
  private static final org.slf4j.Logger ourLog =
      org.slf4j.LoggerFactory.getLogger(ModelExtensionTest.class);
  private FhirContext ourCtx = FhirContext.forDstu1();

  @Test
  public void testModelExtension() throws DataFormatException {
    MyOrganization org = new MyOrganization();
    org.getName().setValue("org0");

    MyPatient patient = new MyPatient();
    patient.addIdentifier("foo", "bar");
    patient.getManagingOrganization().setResource(org);

    IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
    String str = p.encodeResourceToString(patient);

    ourLog.info(str);

    MyPatient parsed = ourCtx.newXmlParser().parseResource(MyPatient.class, str);
    assertEquals("foo", parsed.getIdentifierFirstRep().getSystem().getValueAsString());

    //		assertEquals(MyOrganization.class,
    // parsed.getManagingOrganization().getResource().getClass());
    //		MyOrganization parsedOrg = (MyOrganization) parsed.getManagingOrganization().getResource();
    //		assertEquals("arg0", parsedOrg.getName().getValue());
  }

  @AfterClass
  public static void afterClassClearContext() {
    TestUtil.clearAllStaticFieldsForUnitTest();
  }
}
Ejemplo n.º 2
0
public class UpdateDstu1Test {
  private static CloseableHttpClient ourClient;
  private static FhirContext ourCtx = FhirContext.forDstu1();
  private static final org.slf4j.Logger ourLog =
      org.slf4j.LoggerFactory.getLogger(UpdateDstu1Test.class);
  private static int ourPort;
  private static DiagnosticReportProvider ourReportProvider;
  private static Server ourServer;

  @Test
  public void testUpdate() throws Exception {

    Patient patient = new Patient();
    patient.addIdentifier().setValue("002");

    HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/Patient/001");
    httpPost.setEntity(
        new StringEntity(
            ourCtx.newXmlParser().encodeResourceToString(patient),
            ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));

    HttpResponse status = ourClient.execute(httpPost);

    String responseContent = IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());

    ourLog.info("Response was:\n{}", responseContent);

    OperationOutcome oo =
        ourCtx.newXmlParser().parseResource(OperationOutcome.class, responseContent);
    assertEquals("OODETAILS", oo.getIssueFirstRep().getDetails().getValue());

    assertEquals(200, status.getStatusLine().getStatusCode());
    assertEquals(
        "http://localhost:" + ourPort + "/Patient/001/_history/002",
        status.getFirstHeader("location").getValue());
    assertEquals(
        "http://localhost:" + ourPort + "/Patient/001/_history/002",
        status.getFirstHeader("content-location").getValue());
  }

  @Test
  public void testUpdateWithWrongResourceType() throws Exception {

    Patient patient = new Patient();
    patient.addIdentifier().setValue("002");

    HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/AAAAAA");
    httpPost.setEntity(
        new StringEntity(
            ourCtx.newXmlParser().encodeResourceToString(patient),
            ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));

    HttpResponse status = ourClient.execute(httpPost);

    String responseContent = IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());

    ourLog.info("Response was:\n{}", responseContent);

    assertEquals(400, status.getStatusLine().getStatusCode());

    String expected =
        "<OperationOutcome xmlns=\"http://hl7.org/fhir\"><issue><severity value=\"error\"/><details value=\"Failed to parse request body as XML resource. Error was: DataFormatException at [[row,col {unknown-source}]: [1,1]]: Incorrect resource type found, expected &quot;DiagnosticReport&quot; but found &quot;Patient&quot;\"/></issue></OperationOutcome>";
    assertEquals(expected, responseContent);
  }

  @Test
  public void testUpdateNoResponse() throws Exception {

    DiagnosticReport dr = new DiagnosticReport();
    dr.setId("001");
    dr.addCodedDiagnosis().addCoding().setCode("AAA");

    String encoded = ourCtx.newXmlParser().encodeResourceToString(dr);
    ourLog.info("OUT: {}", encoded);

    HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001");
    httpPost.setEntity(
        new StringEntity(encoded, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));

    HttpResponse status = ourClient.execute(httpPost);
    try {
      ourLog.info(IOUtils.toString(status.getEntity().getContent()));
      assertEquals(200, status.getStatusLine().getStatusCode());
      assertEquals(
          "http://localhost:" + ourPort + "/DiagnosticReport/001/_history/002",
          status.getFirstHeader("location").getValue());
    } finally {
      IOUtils.closeQuietly(status.getEntity().getContent());
    }
  }

  @Test
  public void testUpdateWhichReturnsCreate() throws Exception {

    Patient patient = new Patient();
    patient.addIdentifier().setValue("002");

    HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/Patient/001CREATE");
    httpPost.setEntity(
        new StringEntity(
            ourCtx.newXmlParser().encodeResourceToString(patient),
            ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));

    HttpResponse status = ourClient.execute(httpPost);

    String responseContent = IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());

    ourLog.info("Response was:\n{}", responseContent);

    OperationOutcome oo =
        ourCtx.newXmlParser().parseResource(OperationOutcome.class, responseContent);
    assertEquals("OODETAILS", oo.getIssueFirstRep().getDetails().getValue());

    assertEquals(201, status.getStatusLine().getStatusCode());
    assertEquals(
        "http://localhost:" + ourPort + "/Patient/001CREATE/_history/002",
        status.getFirstHeader("location").getValue());
  }

  @Test
  public void testUpdateWithNoReturn() throws Exception {

    Organization dr = new Organization();
    dr.setId("001");
    dr.addIdentifier().setValue("002");

    HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/Organization/001");
    httpPost.setEntity(
        new StringEntity(
            ourCtx.newXmlParser().encodeResourceToString(dr),
            ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));

    CloseableHttpResponse status = ourClient.execute(httpPost);
    IOUtils.closeQuietly(status.getEntity().getContent());

    assertEquals(200, status.getStatusLine().getStatusCode());
    status.close();
  }

  @Test
  public void testUpdateWithTagMultiple() throws Exception {

    DiagnosticReport dr = new DiagnosticReport();
    dr.setId("001");
    dr.addCodedDiagnosis().addCoding().setCode("AAA");

    HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001");
    httpPost.addHeader("Category", "Dog; scheme=\"urn:animals\", Cat; scheme=\"urn:animals\"");
    httpPost.setEntity(
        new StringEntity(
            ourCtx.newXmlParser().encodeResourceToString(dr),
            ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
    CloseableHttpResponse status = ourClient.execute(httpPost);
    IOUtils.closeQuietly(status.getEntity().getContent());

    assertEquals(2, ourReportProvider.getLastTags().size());
    assertEquals(new Tag("urn:animals", "Dog"), ourReportProvider.getLastTags().get(0));
    assertEquals(new Tag("urn:animals", "Cat"), ourReportProvider.getLastTags().get(1));

    httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001");
    httpPost.addHeader(
        "Category",
        "Dog; label=\"aa\"; scheme=\"urn:animals\", Cat; label=\"bb\"; scheme=\"urn:animals\"");
    httpPost.setEntity(
        new StringEntity(
            ourCtx.newXmlParser().encodeResourceToString(dr),
            ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
    status = ourClient.execute(httpPost);
    IOUtils.closeQuietly(status.getEntity().getContent());

    assertEquals(2, ourReportProvider.getLastTags().size());
    assertEquals(new Tag("urn:animals", "Dog", "aa"), ourReportProvider.getLastTags().get(0));
    assertEquals(new Tag("urn:animals", "Cat", "bb"), ourReportProvider.getLastTags().get(1));
  }

  @Test
  public void testUpdateWithTagSimple() throws Exception {

    DiagnosticReport dr = new DiagnosticReport();
    dr.setId("001");
    dr.addCodedDiagnosis().addCoding().setCode("AAA");

    HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001");
    httpPost.addHeader("Category", "Dog; scheme=\"animals\"");
    httpPost.setEntity(
        new StringEntity(
            ourCtx.newXmlParser().encodeResourceToString(dr),
            ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
    CloseableHttpResponse status = ourClient.execute(httpPost);
    IOUtils.closeQuietly(status.getEntity().getContent());

    assertEquals(1, ourReportProvider.getLastTags().size());
    assertEquals(new Tag("animals", "Dog"), ourReportProvider.getLastTags().get(0));
  }

  @Test
  public void testUpdateWithTagWithScheme() throws Exception {

    DiagnosticReport dr = new DiagnosticReport();
    dr.setId("001");
    dr.addCodedDiagnosis().addCoding().setCode("AAA");

    HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001");
    httpPost.addHeader("Category", "Dog; scheme=\"http://foo\"");
    httpPost.setEntity(
        new StringEntity(
            ourCtx.newXmlParser().encodeResourceToString(dr),
            ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
    CloseableHttpResponse status = ourClient.execute(httpPost);
    IOUtils.closeQuietly(status.getEntity().getContent());

    assertEquals(1, ourReportProvider.getLastTags().size());
    assertEquals(new Tag("http://foo", "Dog", null), ourReportProvider.getLastTags().get(0));

    httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001");
    httpPost.addHeader("Category", "Dog; scheme=\"http://foo\";");
    httpPost.setEntity(
        new StringEntity(
            ourCtx.newXmlParser().encodeResourceToString(dr),
            ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
    ourClient.execute(httpPost);
    IOUtils.closeQuietly(status.getEntity().getContent());

    assertEquals(1, ourReportProvider.getLastTags().size());
    assertEquals(new Tag("http://foo", "Dog", null), ourReportProvider.getLastTags().get(0));
  }

  @Test
  public void testUpdateWithTagWithSchemeAndLabel() throws Exception {

    DiagnosticReport dr = new DiagnosticReport();
    dr.setId("001");
    dr.addCodedDiagnosis().addCoding().setCode("AAA");

    HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001");
    httpPost.addHeader("Category", "Dog; scheme=\"http://foo\"; label=\"aaaa\"");
    httpPost.setEntity(
        new StringEntity(
            ourCtx.newXmlParser().encodeResourceToString(dr),
            ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
    CloseableHttpResponse status = ourClient.execute(httpPost);
    assertEquals(1, ourReportProvider.getLastTags().size());
    assertEquals(new Tag("http://foo", "Dog", "aaaa"), ourReportProvider.getLastTags().get(0));
    IOUtils.closeQuietly(status.getEntity().getContent());

    httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001");
    httpPost.addHeader("Category", "Dog; scheme=\"http://foo\"; label=\"aaaa\";   ");
    httpPost.setEntity(
        new StringEntity(
            ourCtx.newXmlParser().encodeResourceToString(dr),
            ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
    status = ourClient.execute(httpPost);
    IOUtils.closeQuietly(status.getEntity().getContent());

    assertEquals(1, ourReportProvider.getLastTags().size());
    assertEquals(new Tag("http://foo", "Dog", "aaaa"), ourReportProvider.getLastTags().get(0));
  }

  @Test
  public void testUpdateWithVersion() throws Exception {

    DiagnosticReport dr = new DiagnosticReport();
    dr.setId("001");
    dr.getIdentifier().setValue("001");

    HttpPut httpPut = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001");
    httpPut.addHeader("Content-Location", "/DiagnosticReport/001/_history/004");
    httpPut.setEntity(
        new StringEntity(
            ourCtx.newXmlParser().encodeResourceToString(dr),
            ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));

    HttpResponse status = ourClient.execute(httpPut);
    IOUtils.closeQuietly(status.getEntity().getContent());

    // String responseContent =
    // IOUtils.toString(status.getEntity().getContent());
    // ourLog.info("Response was:\n{}", responseContent);

    assertEquals(200, status.getStatusLine().getStatusCode());
    assertEquals(
        "http://localhost:" + ourPort + "/DiagnosticReport/001/_history/002",
        status.getFirstHeader("Location").getValue());
  }

  @Test()
  public void testUpdateWithVersionBadContentLocationHeader() throws Exception {

    DiagnosticReport dr = new DiagnosticReport();
    dr.setId("001");
    dr.getIdentifier().setValue("001");

    HttpPut httpPut = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001");
    httpPut.addHeader("Content-Location", "/Patient/001/_history/002");
    httpPut.setEntity(
        new StringEntity(
            ourCtx.newXmlParser().encodeResourceToString(dr),
            ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));

    CloseableHttpResponse status = ourClient.execute(httpPut);
    String responseContent = IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());

    assertEquals(400, status.getStatusLine().getStatusCode());
    ourLog.info("Response was:\n{}", responseContent);
  }

  public void testUpdateWrongResourceType() throws Exception {

    // TODO: this method sends in the wrong resource type vs. the URL so it
    // should
    // give a useful error message (and then make this unit test actually
    // run)
    Patient patient = new Patient();
    patient.addIdentifier().setValue("002");

    HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001");
    httpPost.setEntity(
        new StringEntity(
            ourCtx.newXmlParser().encodeResourceToString(patient),
            ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));

    ourClient.execute(httpPost);
    fail();
  }

  @AfterClass
  public static void afterClassClearContext() throws Exception {
    ourServer.stop();
    TestUtil.clearAllStaticFieldsForUnitTest();
  }

  @BeforeClass
  public static void beforeClass() throws Exception {
    ourPort = PortUtil.findFreePort();
    ourServer = new Server(ourPort);

    PatientProvider patientProvider = new PatientProvider();

    ourReportProvider = new DiagnosticReportProvider();

    ServletHandler proxyHandler = new ServletHandler();
    RestfulServer servlet = new RestfulServer(ourCtx);
    servlet.setResourceProviders(
        patientProvider,
        ourReportProvider,
        new ObservationProvider(),
        new OrganizationResourceProvider());
    ServletHolder servletHolder = new ServletHolder(servlet);
    proxyHandler.addServletWithMapping(servletHolder, "/*");
    ourServer.setHandler(proxyHandler);
    ourServer.start();

    PoolingHttpClientConnectionManager connectionManager =
        new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
    HttpClientBuilder builder = HttpClientBuilder.create();
    builder.setConnectionManager(connectionManager);
    ourClient = builder.build();
  }

  public static class DiagnosticReportProvider implements IResourceProvider {
    private TagList myLastTags;

    public TagList getLastTags() {
      return myLastTags;
    }

    @Override
    public Class<? extends IResource> getResourceType() {
      return DiagnosticReport.class;
    }

    @Update()
    public MethodOutcome updateDiagnosticReportWithVersionAndNoResponse(
        @IdParam IdDt theId, @ResourceParam DiagnosticReport theDr) {
      IdDt id = theId;

      if (theId.getValue().contains("AAAAAA")) {
        IdDt id2 = new IdDt(id.getIdPart(), "002");
        return new MethodOutcome(id2); // this is invalid
      }

      myLastTags = (TagList) theDr.getResourceMetadata().get(ResourceMetadataKeyEnum.TAG_LIST);
      return new MethodOutcome(new IdDt("DiagnosticReport", id.getIdPart(), "002"));
    }
  }

  public static class ObservationProvider implements IResourceProvider {

    @Override
    public Class<? extends IResource> getResourceType() {
      return Observation.class;
    }

    @Update()
    public MethodOutcome updateDiagnosticReportWithVersion(
        @IdParam IdDt theId, @ResourceParam DiagnosticOrder thePatient) {
      /*
       * TODO: THIS METHOD IS NOT USED. It's the wrong type (DiagnosticOrder), so it should cause an exception on
       * startup. Also we should detect if there are multiple resource params on an
       * update/create/etc method
       */
      IdDt id = theId;
      return new MethodOutcome(id);
    }
  }

  public static class OrganizationResourceProvider implements IResourceProvider {

    @Override
    public Class<? extends IResource> getResourceType() {
      return Organization.class;
    }

    @SuppressWarnings("unused")
    @Update
    public MethodOutcome update(@IdParam IdDt theId, @ResourceParam Organization theOrganization) {
      return new MethodOutcome();
    }
  }

  public static class PatientProvider implements IResourceProvider {

    @Override
    public Class<? extends IResource> getResourceType() {
      return Patient.class;
    }

    @Update()
    public MethodOutcome updatePatient(@IdParam IdDt theId, @ResourceParam Patient thePatient) {
      IdDt id = theId.withVersion(thePatient.getIdentifierFirstRep().getValue().getValue());
      OperationOutcome oo = new OperationOutcome();
      oo.addIssue().setDetails("OODETAILS");
      if (theId.getValueAsString().contains("CREATE")) {
        return new MethodOutcome(id, oo, true);
      }

      return new MethodOutcome(id, oo);
    }
  }
}
Ejemplo n.º 3
0
public class AuditingInterceptorTest {

  private static CloseableHttpClient ourClient;
  private static FhirContext ourCtx = FhirContext.forDstu1();
  private static int ourPort;
  private static Server ourServer;
  private static RestfulServer servlet;
  private IServerInterceptor myInterceptor;

  @Before
  public void before() {
    myInterceptor = mock(IServerInterceptor.class);
    servlet.setInterceptors(Collections.singletonList(myInterceptor));
  }

  @Test
  public void testBundle() throws Exception {

    AuditingInterceptor interceptor = new AuditingInterceptor("HAPITEST", false);
    Map<String, Class<? extends IResourceAuditor<? extends IResource>>> auditors =
        new HashMap<String, Class<? extends IResourceAuditor<? extends IResource>>>();
    auditors.put("Patient", PatientAuditor.class);
    interceptor.setAuditableResources(auditors);
    servlet.setInterceptors(Collections.singletonList((IServerInterceptor) interceptor));

    MockDataStore mockDataStore = mock(MockDataStore.class);
    interceptor.setDataStore(mockDataStore);

    String requestURL = "http://localhost:" + ourPort + "/Patient?_id=1,2";
    HttpGet httpGet = new HttpGet(requestURL);
    httpGet.addHeader(UserInfoInterceptor.HEADER_USER_ID, "hapi-fhir-junit-user");
    httpGet.addHeader(UserInfoInterceptor.HEADER_USER_NAME, "HAPI FHIR Junit Test Cases");
    httpGet.addHeader(UserInfoInterceptor.HEADER_APPLICATION_NAME, "hapi-fhir-junit");

    HttpResponse status = ourClient.execute(httpGet);
    IOUtils.closeQuietly(status.getEntity().getContent());

    ArgumentCaptor<SecurityEvent> captor = ArgumentCaptor.forClass(SecurityEvent.class);

    verify(mockDataStore, times(1)).store(captor.capture());

    SecurityEvent auditEvent = captor.getValue();
    assertEquals(
        SecurityEventOutcomeEnum.SUCCESS.getCode(), auditEvent.getEvent().getOutcome().getValue());
    assertEquals(
        "HAPI FHIR Junit Test Cases", auditEvent.getParticipantFirstRep().getName().getValue());
    assertEquals(
        "hapi-fhir-junit-user", auditEvent.getParticipantFirstRep().getUserId().getValue());
    assertEquals("hapi-fhir-junit", auditEvent.getSource().getIdentifier().getValue());
    assertEquals("HAPITEST", auditEvent.getSource().getSite().getValue());
    assertEquals(
        SecurityEventSourceTypeEnum.USER_DEVICE.getCode(),
        auditEvent.getSource().getTypeFirstRep().getCode().getValue());

    List<ObjectElement> objects = auditEvent.getObject();
    assertEquals(2, objects.size());

    for (ObjectElement object : objects) {
      if ("00001".equals(object.getIdentifier().getValue().getValue())) {
        assertEquals("Patient: PatientOne Test", object.getName().getValue());
      } else if ("00002".equals(object.getIdentifier().getValue().getValue())) {
        assertEquals(
            "Patient: Ms Laura Elizabeth MacDougall Sookraj B.Sc.", object.getName().getValue());
      } else {
        fail(
            "Unexpected patient identifier being audited: "
                + object.getIdentifier().getValue().getValue());
      }
      assertEquals(
          requestURL, new String(Base64.decodeBase64(object.getQuery().getValueAsString())));
      assertEquals(SecurityEventObjectTypeEnum.PERSON, object.getType().getValueAsEnum());
    }
  }

  @Test
  public void testSinglePatient() throws Exception {

    AuditingInterceptor interceptor = new AuditingInterceptor("HAPITEST", false);
    Map<String, Class<? extends IResourceAuditor<? extends IResource>>> auditors =
        new HashMap<String, Class<? extends IResourceAuditor<? extends IResource>>>();
    auditors.put("Patient", PatientAuditor.class);
    interceptor.setAuditableResources(auditors);
    servlet.setInterceptors(Collections.singletonList((IServerInterceptor) interceptor));

    MockDataStore mockDataStore = mock(MockDataStore.class);
    interceptor.setDataStore(mockDataStore);

    String requestURL = "http://localhost:" + ourPort + "/Patient/1";
    HttpGet httpGet = new HttpGet(requestURL);
    httpGet.addHeader(UserInfoInterceptor.HEADER_USER_ID, "hapi-fhir-junit-user");
    httpGet.addHeader(UserInfoInterceptor.HEADER_USER_NAME, "HAPI FHIR Junit Test Cases");
    httpGet.addHeader(UserInfoInterceptor.HEADER_APPLICATION_NAME, "hapi-fhir-junit");

    HttpResponse status = ourClient.execute(httpGet);
    IOUtils.closeQuietly(status.getEntity().getContent());

    ArgumentCaptor<SecurityEvent> captor = ArgumentCaptor.forClass(SecurityEvent.class);

    verify(mockDataStore, times(1)).store(captor.capture());

    SecurityEvent auditEvent = captor.getValue();
    assertEquals(
        SecurityEventOutcomeEnum.SUCCESS.getCode(), auditEvent.getEvent().getOutcome().getValue());
    assertEquals(
        "HAPI FHIR Junit Test Cases", auditEvent.getParticipantFirstRep().getName().getValue());
    assertEquals(
        "hapi-fhir-junit-user", auditEvent.getParticipantFirstRep().getUserId().getValue());
    assertEquals("hapi-fhir-junit", auditEvent.getSource().getIdentifier().getValue());
    assertEquals("HAPITEST", auditEvent.getSource().getSite().getValue());
    assertEquals(
        SecurityEventSourceTypeEnum.USER_DEVICE.getCode(),
        auditEvent.getSource().getTypeFirstRep().getCode().getValue());

    List<ObjectElement> objects = auditEvent.getObject();
    assertEquals(1, objects.size());
    ObjectElement object = objects.get(0);
    assertEquals("00001", object.getIdentifier().getValue().getValue());
    assertEquals("Patient: PatientOne Test", object.getName().getValue());
    assertEquals(
        SecurityEventObjectLifecycleEnum.ACCESS_OR_USE, object.getLifecycle().getValueAsEnum());
    assertEquals(SecurityEventObjectTypeEnum.PERSON, object.getType().getValueAsEnum());
    assertEquals(requestURL, new String(Base64.decodeBase64(object.getQuery().getValueAsString())));
  }

  @AfterClass
  public static void afterClassClearContext() throws Exception {
    ourServer.stop();
    TestUtil.clearAllStaticFieldsForUnitTest();
  }

  @BeforeClass
  public static void beforeClass() throws Exception {
    ourPort = PortUtil.findFreePort();
    ourServer = new Server(ourPort);

    DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();

    ServletHandler proxyHandler = new ServletHandler();
    servlet = new RestfulServer(ourCtx);
    servlet.setResourceProviders(patientProvider);
    ServletHolder servletHolder = new ServletHolder(servlet);
    proxyHandler.addServletWithMapping(servletHolder, "/*");
    ourServer.setHandler(proxyHandler);
    ourServer.start();

    PoolingHttpClientConnectionManager connectionManager =
        new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
    HttpClientBuilder builder = HttpClientBuilder.create();
    builder.setConnectionManager(connectionManager);
    ourClient = builder.build();
  }

  public static class DummyPatientResourceProvider implements IResourceProvider {

    private Patient createPatient1() {
      Patient patient = new Patient();
      patient.addIdentifier();
      patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL);
      patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns"));
      patient.getIdentifier().get(0).setValue("00001");
      patient.addName();
      patient.getName().get(0).addFamily("Test");
      patient.getName().get(0).addGiven("PatientOne");
      patient.getGender().setText("M");
      patient.getId().setValue("1");
      return patient;
    }

    public Map<String, Patient> getIdToPatient() {
      Map<String, Patient> idToPatient = new HashMap<String, Patient>();
      {
        Patient patient = createPatient1();
        idToPatient.put("1", patient);
      }
      {
        Patient patient = new Patient();
        patient.getIdentifier().add(new IdentifierDt());
        patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL);
        patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns"));
        patient.getIdentifier().get(0).setValue("00002");
        HumanNameDt name = new HumanNameDt();
        name.addPrefix("Ms");
        name.addGiven("Laura");
        name.addGiven("Elizabeth");
        name.addFamily("MacDougall");
        name.addFamily("Sookraj");
        name.addSuffix("B.Sc.");
        patient.getName().add(name);
        patient.getGender().setText("F");
        patient.getId().setValue("2");
        idToPatient.put("2", patient);
      }
      return idToPatient;
    }

    /**
     * Retrieve the resource by its identifier
     *
     * @param theId The resource identity
     * @return The resource
     */
    @Read()
    public Patient getResourceById(@IdParam IdDt theId) {
      String key = theId.getIdPart();
      Patient retVal = getIdToPatient().get(key);
      return retVal;
    }

    /**
     * Retrieve the resource by its identifier
     *
     * @param theId The resource identity
     * @return The resource
     */
    @Search()
    public List<Patient> getResourceById(@RequiredParam(name = "_id") TokenOrListParam theIds) {
      List<Patient> patients = new ArrayList<Patient>();
      for (BaseCodingDt id : theIds.getListAsCodings()) {
        Patient patient = getIdToPatient().get(id.getCodeElement().getValue());
        if (patient != null) {
          patients.add(patient);
        }
      }
      return patients;
    }

    @Override
    public Class<Patient> getResourceType() {
      return Patient.class;
    }
  }

  private class MockDataStore implements IAuditDataStore {

    @Override
    public void store(BaseSecurityEvent auditEvent) throws Exception {
      // do nothing
    }
  }
}
public class SearchSearchServerDstu1Test {

  private static CloseableHttpClient ourClient;
  private static FhirContext ourCtx = FhirContext.forDstu1();
  private static final org.slf4j.Logger ourLog =
      org.slf4j.LoggerFactory.getLogger(SearchSearchServerDstu1Test.class);
  private static int ourPort;

  private static Server ourServer;
  private static RestfulServer ourServlet;
  private static IServerAddressStrategy ourDefaultAddressStrategy;
  private static Set<Include> ourLastIncludes;
  private static StringAndListParam ourLastAndList;

  @Before
  public void before() {
    ourServlet.setServerAddressStrategy(ourDefaultAddressStrategy);
    ourLastIncludes = null;
    ourLastAndList = null;
  }

  @Test
  public void testParseEscapedValues() throws Exception {

    StringBuilder b = new StringBuilder();
    b.append("http://localhost:");
    b.append(ourPort);
    b.append("/Patient?");
    b.append(escape("findPatientWithAndList"))
        .append('=')
        .append(escape("NE\\,NE,NE\\,NE"))
        .append('&');
    b.append(escape("findPatientWithAndList")).append('=').append(escape("NE\\\\NE")).append('&');
    b.append(escape("findPatientWithAndList:exact"))
        .append('=')
        .append(escape("E\\$E"))
        .append('&');
    b.append(escape("findPatientWithAndList:exact"))
        .append('=')
        .append(escape("E\\|E"))
        .append('&');

    HttpGet httpGet = new HttpGet(b.toString());

    HttpResponse status = ourClient.execute(httpGet);
    String responseContent = IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());
    ourLog.info(responseContent);

    assertEquals(200, status.getStatusLine().getStatusCode());

    assertEquals(4, ourLastAndList.getValuesAsQueryTokens().size());
    assertEquals(2, ourLastAndList.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().size());
    assertFalse(
        ourLastAndList.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).isExact());
    assertEquals(
        "NE,NE",
        ourLastAndList.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValue());
    assertEquals(
        "NE,NE",
        ourLastAndList.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(1).getValue());
    assertEquals(
        "NE\\NE",
        ourLastAndList.getValuesAsQueryTokens().get(1).getValuesAsQueryTokens().get(0).getValue());
    assertTrue(
        ourLastAndList.getValuesAsQueryTokens().get(2).getValuesAsQueryTokens().get(0).isExact());
    assertEquals(
        "E$E",
        ourLastAndList.getValuesAsQueryTokens().get(2).getValuesAsQueryTokens().get(0).getValue());
    assertEquals(
        "E|E",
        ourLastAndList.getValuesAsQueryTokens().get(3).getValuesAsQueryTokens().get(0).getValue());
  }

  @Test
  public void testEncodeConvertsReferencesToRelative() throws Exception {
    HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchWithRef");
    HttpResponse status = ourClient.execute(httpGet);
    String responseContent = IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());
    ourLog.info(responseContent);

    assertEquals(200, status.getStatusLine().getStatusCode());
    Patient patient =
        (Patient)
            ourCtx.newXmlParser().parseBundle(responseContent).getEntries().get(0).getResource();
    String ref = patient.getManagingOrganization().getReference().getValue();
    assertEquals("Organization/555", ref);
  }

  @Test
  public void testOmitEmptyOptionalParam() throws Exception {
    HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_id=");
    HttpResponse status = ourClient.execute(httpGet);
    String responseContent = IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());
    assertEquals(200, status.getStatusLine().getStatusCode());
    Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
    assertEquals(1, bundle.getEntries().size());

    Patient p = bundle.getResources(Patient.class).get(0);
    assertEquals(null, p.getNameFirstRep().getFamilyFirstRep().getValue());
  }

  @Test
  public void testReturnLinks() throws Exception {
    HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=findWithLinks");

    CloseableHttpResponse status = ourClient.execute(httpGet);
    String responseContent = IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());
    assertEquals(200, status.getStatusLine().getStatusCode());
    Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
    assertEquals(10, bundle.getEntries().size());

    Patient p = bundle.getResources(Patient.class).get(0);
    assertEquals("AAANamed", p.getIdentifierFirstRep().getValue().getValue());
    assertEquals("http://foo/Patient?_id=1", bundle.getEntries().get(0).getLinkSearch().getValue());
    assertEquals(
        "http://localhost:" + ourPort + "/Patient/99881",
        bundle.getEntries().get(0).getLinkAlternate().getValue());

    assertEquals("http://foo/Patient?_id=1", ResourceMetadataKeyEnum.LINK_SEARCH.get(p));
    assertEquals(
        "http://localhost:" + ourPort + "/Patient/99881",
        ResourceMetadataKeyEnum.LINK_ALTERNATE.get(p));
  }

  @Test
  public void testSearchIncludesParametersNone() throws Exception {
    HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchIncludes");

    CloseableHttpResponse status = ourClient.execute(httpGet);
    IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());
    assertEquals(200, status.getStatusLine().getStatusCode());

    assertThat(ourLastIncludes, empty());
  }

  @Test
  public void testSearchIncludesParametersIncludes() throws Exception {
    HttpGet httpGet =
        new HttpGet(
            "http://localhost:"
                + ourPort
                + "/Patient?_query=searchIncludes&_include=foo&_include:recurse=bar");

    CloseableHttpResponse status = ourClient.execute(httpGet);
    IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());
    assertEquals(200, status.getStatusLine().getStatusCode());

    assertEquals(2, ourLastIncludes.size());
    assertThat(
        ourLastIncludes, containsInAnyOrder(new Include("foo", false), new Include("bar", true)));
  }

  @Test
  public void testSearchIncludesParametersIncludesList() throws Exception {
    HttpGet httpGet =
        new HttpGet(
            "http://localhost:"
                + ourPort
                + "/Patient?_query=searchIncludesList&_include=foo&_include:recurse=bar");

    CloseableHttpResponse status = ourClient.execute(httpGet);
    IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());
    assertEquals(200, status.getStatusLine().getStatusCode());

    assertEquals(2, ourLastIncludes.size());
    assertThat(
        ourLastIncludes, containsInAnyOrder(new Include("foo", false), new Include("bar", true)));
  }

  /** #149 */
  @Test
  public void testReturnLinksWithAddressStrategy() throws Exception {
    ourServlet.setServerAddressStrategy(
        new HardcodedServerAddressStrategy("https://blah.com/base"));

    HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=findWithLinks");

    CloseableHttpResponse status = ourClient.execute(httpGet);
    String responseContent = IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());
    assertEquals(200, status.getStatusLine().getStatusCode());
    Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);

    ourLog.info(responseContent);

    assertEquals(10, bundle.getEntries().size());
    assertEquals("https://blah.com/base", bundle.getLinkBase().getValue());
    assertEquals(
        "https://blah.com/base/Patient?_query=findWithLinks", bundle.getLinkSelf().getValue());

    Patient p = bundle.getResources(Patient.class).get(0);
    assertEquals("AAANamed", p.getIdentifierFirstRep().getValue().getValue());
    assertEquals("http://foo/Patient?_id=1", bundle.getEntries().get(0).getLinkSearch().getValue());
    assertEquals(
        "https://blah.com/base/Patient/99881",
        bundle.getEntries().get(0).getLinkAlternate().getValue());
    assertEquals("http://foo/Patient?_id=1", ResourceMetadataKeyEnum.LINK_SEARCH.get(p));
    assertEquals(
        "https://blah.com/base/Patient/99881", ResourceMetadataKeyEnum.LINK_ALTERNATE.get(p));

    String linkNext = bundle.getLinkNext().getValue();
    ourLog.info(linkNext);
    assertThat(linkNext, startsWith("https://blah.com/base?_getpages="));

    /*
     * Load the second page
     */
    String urlPart = linkNext.substring(linkNext.indexOf('?'));
    String link = "http://localhost:" + ourPort + urlPart;
    httpGet = new HttpGet(link);

    status = ourClient.execute(httpGet);
    responseContent = IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());
    assertEquals(200, status.getStatusLine().getStatusCode());
    bundle = ourCtx.newXmlParser().parseBundle(responseContent);

    ourLog.info(responseContent);

    assertEquals(10, bundle.getEntries().size());
    assertEquals("https://blah.com/base", bundle.getLinkBase().getValue());
    assertEquals(linkNext, bundle.getLinkSelf().getValue());

    p = bundle.getResources(Patient.class).get(0);
    assertEquals("AAANamed", p.getIdentifierFirstRep().getValue().getValue());
    assertEquals(
        "http://foo/Patient?_id=11", bundle.getEntries().get(0).getLinkSearch().getValue());
    assertEquals(
        "https://blah.com/base/Patient/998811",
        bundle.getEntries().get(0).getLinkAlternate().getValue());
    assertEquals("http://foo/Patient?_id=11", ResourceMetadataKeyEnum.LINK_SEARCH.get(p));
    assertEquals(
        "https://blah.com/base/Patient/998811", ResourceMetadataKeyEnum.LINK_ALTERNATE.get(p));
  }

  /** Try loading the page as a POST just to make sure we get the right error */
  @Test
  public void testGetPagesWithPost() throws Exception {

    HttpPost httpPost = new HttpPost("http://localhost:" + ourPort);
    List<? extends NameValuePair> parameters =
        Collections.singletonList(new BasicNameValuePair("_getpages", "AAA"));
    httpPost.setEntity(new UrlEncodedFormEntity(parameters));

    CloseableHttpResponse status = ourClient.execute(httpPost);
    String responseContent = IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());
    ourLog.info(responseContent);
    assertEquals(400, status.getStatusLine().getStatusCode());
    assertThat(responseContent, containsString("Requests for _getpages must use HTTP GET"));
  }

  @Test
  public void testSearchById() throws Exception {
    HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_id=aaa");
    HttpResponse status = ourClient.execute(httpGet);
    String responseContent = IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());
    assertEquals(200, status.getStatusLine().getStatusCode());
    Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
    assertEquals(1, bundle.getEntries().size());

    Patient p = bundle.getResources(Patient.class).get(0);
    assertEquals("idaaa", p.getNameFirstRep().getFamilyAsSingleString());
    assertEquals("IDAAA (identifier123)", bundle.getEntries().get(0).getTitle().getValue());
  }

  @Test
  public void testSearchByIdUsingClient() throws Exception {
    IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort);

    Bundle bundle =
        client
            .search()
            .forResource("Patient")
            .where(BaseResource.RES_ID.matches().value("aaa"))
            .execute();
    assertEquals(1, bundle.getEntries().size());

    Patient p = bundle.getResources(Patient.class).get(0);
    assertEquals("idaaa", p.getNameFirstRep().getFamilyAsSingleString());
    assertEquals("IDAAA (identifier123)", bundle.getEntries().get(0).getTitle().getValue());
  }

  @Test
  public void testSearchWithOrList() throws Exception {
    HttpGet httpGet =
        new HttpGet("http://localhost:" + ourPort + "/Patient?findPatientWithOrList=aaa,bbb");
    HttpResponse status = ourClient.execute(httpGet);
    String responseContent = IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());
    assertEquals(200, status.getStatusLine().getStatusCode());
    Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
    assertEquals(1, bundle.getEntries().size());

    Patient p = bundle.getResources(Patient.class).get(0);
    assertEquals("aaa", p.getIdentifier().get(0).getValue().getValue());
    assertEquals("bbb", p.getIdentifier().get(1).getValue().getValue());
  }

  @Test
  public void testSearchWithTokenParameter() throws Exception {
    String token =
        UrlEscapers.urlFragmentEscaper().asFunction().apply("http://www.dmix.gov/vista/2957|301");
    HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?tokenParam=" + token);
    HttpResponse status = ourClient.execute(httpGet);
    String responseContent = IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());
    assertEquals(200, status.getStatusLine().getStatusCode());
    Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
    assertEquals(1, bundle.getEntries().size());

    Patient p = bundle.getResources(Patient.class).get(0);
    assertEquals("http://www.dmix.gov/vista/2957", p.getNameFirstRep().getFamilyAsSingleString());
    assertEquals("301", p.getNameFirstRep().getGivenAsSingleString());
  }

  @Test
  public void testSearchByPost() throws Exception {
    HttpPost filePost = new HttpPost("http://localhost:" + ourPort + "/Patient/_search");

    // add parameters to the post method
    List<NameValuePair> parameters = new ArrayList<NameValuePair>();
    parameters.add(new BasicNameValuePair("_id", "aaa"));

    UrlEncodedFormEntity sendentity = new UrlEncodedFormEntity(parameters, "UTF-8");
    filePost.setEntity(sendentity);

    HttpResponse status = ourClient.execute(filePost);
    String responseContent = IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());
    assertEquals(200, status.getStatusLine().getStatusCode());
    Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
    assertEquals(1, bundle.getEntries().size());

    Patient p = bundle.getResources(Patient.class).get(0);
    assertEquals("idaaa", p.getNameFirstRep().getFamilyAsSingleString());
    assertEquals("IDAAA (identifier123)", bundle.getEntries().get(0).getTitle().getValue());
  }

  /** See #164 */
  @Test
  public void testSearchByPostWithParamsInBodyAndUrl() throws Exception {
    HttpPost filePost =
        new HttpPost("http://localhost:" + ourPort + "/Patient/_search?name=Central");

    // add parameters to the post method
    List<NameValuePair> parameters = new ArrayList<NameValuePair>();
    parameters.add(new BasicNameValuePair("_id", "aaa"));

    UrlEncodedFormEntity sendentity = new UrlEncodedFormEntity(parameters, "UTF-8");
    filePost.setEntity(sendentity);

    HttpResponse status = ourClient.execute(filePost);
    String responseContent = IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());
    ourLog.info(responseContent);
    assertEquals(200, status.getStatusLine().getStatusCode());

    Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
    assertEquals(1, bundle.getEntries().size());

    Patient p = bundle.getResources(Patient.class).get(0);
    assertEquals("idaaa", p.getName().get(0).getFamilyAsSingleString());
    assertEquals("nameCentral", p.getName().get(1).getFamilyAsSingleString());
  }

  /** See #164 */
  @Test
  public void testSearchByPostWithInvalidPostUrl() throws Exception {
    HttpPost filePost =
        new HttpPost("http://localhost:" + ourPort + "/Patient?name=Central"); // should end with
    // _search

    // add parameters to the post method
    List<NameValuePair> parameters = new ArrayList<NameValuePair>();
    parameters.add(new BasicNameValuePair("_id", "aaa"));

    UrlEncodedFormEntity sendentity = new UrlEncodedFormEntity(parameters, "UTF-8");
    filePost.setEntity(sendentity);

    HttpResponse status = ourClient.execute(filePost);
    String responseContent = IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());
    ourLog.info(responseContent);
    assertEquals(400, status.getStatusLine().getStatusCode());
    assertThat(
        responseContent,
        containsString(
            "<details value=\"Incorrect Content-Type header value of &quot;application/x-www-form-urlencoded; charset=UTF-8&quot; was provided in the request. A FHIR Content-Type is required for &quot;CREATE&quot; operation\"/>"));
  }

  /** See #164 */
  @Test
  public void testSearchByPostWithMissingContentType() throws Exception {
    HttpPost filePost =
        new HttpPost("http://localhost:" + ourPort + "/Patient?name=Central"); // should end with
    // _search

    HttpEntity sendentity = new ByteArrayEntity(new byte[] {1, 2, 3, 4});
    filePost.setEntity(sendentity);

    HttpResponse status = ourClient.execute(filePost);
    String responseContent = IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());
    ourLog.info(responseContent);
    assertEquals(400, status.getStatusLine().getStatusCode());
    assertThat(
        responseContent,
        containsString(
            "<details value=\"No Content-Type header was provided in the request. This is required for &quot;CREATE&quot; operation\"/>"));
  }

  @Test
  public void testSearchCompartment() throws Exception {
    HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/fooCompartment");
    HttpResponse status = ourClient.execute(httpGet);
    String responseContent = IOUtils.toString(status.getEntity().getContent());
    ourLog.info(responseContent);
    IOUtils.closeQuietly(status.getEntity().getContent());
    assertEquals(200, status.getStatusLine().getStatusCode());
    Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
    assertEquals(1, bundle.getEntries().size());

    Patient p = bundle.getResources(Patient.class).get(0);
    assertEquals("fooCompartment", p.getIdentifierFirstRep().getValue().getValue());
    assertThat(
        bundle.getEntries().get(0).getResource().getId().getValue(), containsString("Patient/123"));
  }

  @Test
  public void testSearchGetWithUnderscoreSearch() throws Exception {
    HttpGet httpGet =
        new HttpGet(
            "http://localhost:"
                + ourPort
                + "/Observation/_search?subject%3APatient=100&name=3141-9%2C8302-2%2C8287-5%2C39156-5");

    HttpResponse status = ourClient.execute(httpGet);
    String responseContent = IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());

    assertEquals(200, status.getStatusLine().getStatusCode());
    Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
    assertEquals(1, bundle.getEntries().size());

    Observation p = bundle.getResources(Observation.class).get(0);
    assertEquals("Patient/100", p.getSubject().getReference().toString());
    assertEquals(4, p.getName().getCoding().size());
    assertEquals("3141-9", p.getName().getCoding().get(0).getCode().getValue());
    assertEquals("8302-2", p.getName().getCoding().get(1).getCode().getValue());
  }

  @Test
  public void testSpecificallyNamedQueryGetsPrecedence() throws Exception {
    HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?AAA=123");

    HttpResponse status = ourClient.execute(httpGet);
    String responseContent = IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());
    assertEquals(200, status.getStatusLine().getStatusCode());
    Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
    assertEquals(1, bundle.getEntries().size());

    Patient p = bundle.getResources(Patient.class).get(0);
    assertEquals("AAA", p.getIdentifierFirstRep().getValue().getValue());

    // Now the named query

    httpGet =
        new HttpGet("http://localhost:" + ourPort + "/Patient?_query=findPatientByAAA&AAA=123");

    status = ourClient.execute(httpGet);
    responseContent = IOUtils.toString(status.getEntity().getContent());
    IOUtils.closeQuietly(status.getEntity().getContent());
    assertEquals(200, status.getStatusLine().getStatusCode());
    bundle = ourCtx.newXmlParser().parseBundle(responseContent);
    assertEquals(1, bundle.getEntries().size());

    p = bundle.getResources(Patient.class).get(0);
    assertEquals("AAANamed", p.getIdentifierFirstRep().getValue().getValue());
  }

  @AfterClass
  public static void afterClass() throws Exception {
    ourServer.stop();
  }

  @BeforeClass
  public static void beforeClass() throws Exception {
    ourPort = PortUtil.findFreePort();
    ourServer = new Server(ourPort);

    DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();

    ServletHandler proxyHandler = new ServletHandler();
    ourServlet = new RestfulServer();
    ourServlet.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
    ourServlet.setPagingProvider(new FifoMemoryPagingProvider(10).setDefaultPageSize(10));

    ourServlet.setResourceProviders(patientProvider, new DummyObservationResourceProvider());
    ServletHolder servletHolder = new ServletHolder(ourServlet);
    proxyHandler.addServletWithMapping(servletHolder, "/*");
    ourServer.setHandler(proxyHandler);
    ourServer.start();

    PoolingHttpClientConnectionManager connectionManager =
        new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
    HttpClientBuilder builder = HttpClientBuilder.create();
    builder.setConnectionManager(connectionManager);
    ourClient = builder.build();

    ourDefaultAddressStrategy = ourServlet.getServerAddressStrategy();
  }

  public static class DummyObservationResourceProvider implements IResourceProvider {

    @Override
    public Class<? extends IResource> getResourceType() {
      return Observation.class;
    }

    @Search
    public Observation search(
        @RequiredParam(name = "subject") ReferenceParam theSubject,
        @RequiredParam(name = "name") TokenOrListParam theName) {
      Observation o = new Observation();
      o.setId("1");

      o.getSubject().setReference(theSubject.getResourceType() + "/" + theSubject.getIdPart());
      for (BaseCodingDt next : theName.getListAsCodings()) {
        o.getName().getCoding().add(new CodingDt(next));
      }

      return o;
    }
  }

  public static class DummyPatientResourceProvider implements IResourceProvider {

    /** Only needed for #164 */
    @Create
    public MethodOutcome create(@ResourceParam Patient thePatient) {
      throw new IllegalArgumentException();
    }

    @Search(compartmentName = "fooCompartment")
    public List<Patient> compartment(@IdParam IdDt theId) {
      ArrayList<Patient> retVal = new ArrayList<Patient>();

      Patient patient = new Patient();
      patient.setId(theId);
      patient.addIdentifier("system", "fooCompartment");
      retVal.add(patient);
      return retVal;
    }

    @Search(queryName = "searchWithRef")
    public Patient searchWithRef() {
      Patient patient = new Patient();
      patient.setId("Patient/1/_history/1");
      patient
          .getManagingOrganization()
          .setReference("http://localhost:" + ourPort + "/Organization/555/_history/666");
      return patient;
    }

    @Search
    public List<Patient> findPatient(
        @RequiredParam(name = "_id") StringParam theParam,
        @OptionalParam(name = "name") StringParam theName) {
      ArrayList<Patient> retVal = new ArrayList<Patient>();

      Patient patient = new Patient();
      patient.setId("1");
      patient.addIdentifier("system", "identifier123");
      if (theParam != null) {
        patient.addName().addFamily("id" + theParam.getValue());
        if (theName != null) {
          patient.addName().addFamily("name" + theName.getValue());
        }
      }
      retVal.add(patient);
      return retVal;
    }

    @Search
    public List<Patient> findPatientByAAA01(@RequiredParam(name = "AAA") StringParam theParam) {
      ArrayList<Patient> retVal = new ArrayList<Patient>();

      Patient patient = new Patient();
      patient.setId("1");
      patient.addIdentifier("system", "AAA");
      retVal.add(patient);
      return retVal;
    }

    @Search(queryName = "findPatientByAAA")
    public List<Patient> findPatientByAAA02Named(
        @OptionalParam(name = "AAA") StringParam theParam) {
      ArrayList<Patient> retVal = new ArrayList<Patient>();

      Patient patient = new Patient();
      patient.setId("1");
      patient.addIdentifier("system", "AAANamed");
      retVal.add(patient);
      return retVal;
    }

    @Search()
    public List<Patient> findPatientWithOrList(
        @RequiredParam(name = "findPatientWithOrList") StringOrListParam theParam) {
      ArrayList<Patient> retVal = new ArrayList<Patient>();

      Patient patient = new Patient();
      patient.setId("1");
      for (StringParam next : theParam.getValuesAsQueryTokens()) {
        patient.addIdentifier("system", next.getValue());
      }
      retVal.add(patient);
      return retVal;
    }

    @Search()
    public List<Patient> findPatientWithAndList(
        @RequiredParam(name = "findPatientWithAndList") StringAndListParam theParam) {
      ourLastAndList = theParam;
      ArrayList<Patient> retVal = new ArrayList<Patient>();
      return retVal;
    }

    @Search()
    public List<Patient> findPatientWithToken(
        @RequiredParam(name = "tokenParam") TokenParam theParam) {
      ArrayList<Patient> retVal = new ArrayList<Patient>();

      Patient patient = new Patient();
      patient.setId("1");
      patient.addName().addFamily(theParam.getSystem()).addGiven(theParam.getValue());
      retVal.add(patient);
      return retVal;
    }

    @Search(queryName = "findWithLinks")
    public List<Patient> findWithLinks() {
      ArrayList<Patient> retVal = new ArrayList<Patient>();

      for (int i = 1; i <= 20; i++) {
        Patient patient = new Patient();
        patient.setId("" + i);
        patient.addIdentifier("system", "AAANamed");
        ResourceMetadataKeyEnum.LINK_SEARCH.put(patient, ("http://foo/Patient?_id=" + i));
        ResourceMetadataKeyEnum.LINK_ALTERNATE.put(patient, ("Patient/9988" + i));
        retVal.add(patient);
      }

      return retVal;
    }

    @Search(queryName = "searchIncludes")
    public List<Patient> searchIncludes(@IncludeParam Set<Include> theIncludes) {
      ourLastIncludes = theIncludes;

      ArrayList<Patient> retVal = new ArrayList<Patient>();
      return retVal;
    }

    @Search(queryName = "searchIncludesList")
    public List<Patient> searchIncludesList(@IncludeParam List<Include> theIncludes) {
      if (theIncludes != null) {
        ourLastIncludes = new HashSet<Include>(theIncludes);
      }

      ArrayList<Patient> retVal = new ArrayList<Patient>();
      return retVal;
    }

    @Override
    public Class<? extends IResource> getResourceType() {
      return Patient.class;
    }
  }
}