protected AbstractLightblueProxyServlet getTestServlet(
      CloseableHttpClient httpClient,
      LightblueClientConfiguration clientConfig,
      final String serviceUri,
      ServletConfig servletConfig)
      throws ServletException {
    Instance<LightblueClientConfiguration> instance = new StubInstance<>(clientConfig);

    AbstractLightblueProxyServlet servlet;
    servlet =
        new AbstractLightblueProxyServlet(httpClient, instance) {
          @Override
          protected String serviceUriForRequest(HttpServletRequest request)
              throws ServletException {
            return serviceUri + servicePathForRequest(request);
          };
        };

    if (servletConfig == null) {
      servlet.init();
    } else {
      servlet.init(servletConfig);
    }

    return servlet;
  }
  @Test
  public void shouldRespondWithLightblueServiceResponseBodyThenCloseResponse()
      throws IOException, ServletException {
    CloseableHttpClient mockHttpClient = mock(CloseableHttpClient.class);
    CloseableHttpResponse mockLightblueResponse = mock(CloseableHttpResponse.class);
    HttpEntity mockEntity = mock(HttpEntity.class);

    when(mockHttpClient.execute(any(HttpUriRequest.class))).thenReturn(mockLightblueResponse);
    when(mockLightblueResponse.getEntity()).thenReturn(mockEntity);

    AbstractLightblueProxyServlet servlet =
        getTestServlet(mockHttpClient, null, "http://myservice.com", null);

    HttpServletRequest stubRequest =
        new StubHttpServletRequest(
            "http://test.com/servlet/file", "GET", "{test:0}", "application/json", "/servlet/*");

    HttpServletResponse mockProxyResponse = mock(HttpServletResponse.class);
    ServletOutputStream outputStream = new FakeServletOutputStream(new ByteArrayOutputStream());
    when(mockProxyResponse.getOutputStream()).thenReturn(outputStream);

    servlet.service(stubRequest, mockProxyResponse);

    InOrder inOrder = inOrder(mockEntity, mockLightblueResponse);
    inOrder.verify(mockEntity).writeTo(outputStream);
    inOrder.verify(mockLightblueResponse).close();
  }
  @Test
  public void shouldUseInjectedClientConfigurationIfSatisfied() throws ServletException {
    CloseableHttpClient mockHttpClient =
        mock(CloseableHttpClient.class, Mockito.RETURNS_DEEP_STUBS);
    LightblueClientConfiguration config = new LightblueClientConfiguration();

    AbstractLightblueProxyServlet servlet = getTestServlet(mockHttpClient, config, null, null);

    assertSame(config, servlet.configuration());
  }
  @Test
  public void shouldGetServletInitParamOrDefault() throws ServletException {
    ServletConfig fakeServletConfig =
        new FakeServletConfig().setInitParameter("testParam", "testValue");
    AbstractLightblueProxyServlet servlet =
        getTestServlet(mock(CloseableHttpClient.class), null, null, fakeServletConfig);

    assertEquals("testValue", servlet.getInitParamOrDefault("testParam", "defaultValue"));
    assertEquals(
        "testDefaultValue", servlet.getInitParamOrDefault("nullParam", "testDefaultValue"));
  }
  @Test
  public void shouldDefaultToDefaultPropertiesFileForClientConfigIfNoneIsInjected()
      throws ServletException {
    CloseableHttpClient mockHttpClient =
        mock(CloseableHttpClient.class, Mockito.RETURNS_DEEP_STUBS);

    ServletConfig servletConfig =
        new FakeServletConfig().setServletContext(mock(ServletContext.class));
    AbstractLightblueProxyServlet servlet =
        getTestServlet(mockHttpClient, null, null, servletConfig);

    LightblueClientConfiguration expected = PropertiesLightblueClientConfiguration.fromDefault();

    assertEquals(expected, servlet.configuration());
  }
  @Test
  public void shouldReturnTheServicePathForTheRequest() throws ServletException, IOException {
    CloseableHttpClient mockHttpClient =
        mock(CloseableHttpClient.class, Mockito.RETURNS_DEEP_STUBS);

    AbstractLightblueProxyServlet servlet = getTestServlet(mockHttpClient, null, null, null);

    HttpServletRequest stubRequest =
        new StubHttpServletRequest(
            "http://my.site.com/app/get/the/thing?foo=bar",
            "GET",
            "{test:0}",
            "application/json",
            "/get/*");

    assertEquals("/the/thing?foo=bar", servlet.servicePathForRequest(stubRequest));
  }
  @Test
  public void shouldProxyTheRequestMethodUriBodyAndContentType()
      throws ServletException, IOException, URISyntaxException {
    CloseableHttpClient mockHttpClient =
        mock(CloseableHttpClient.class, Mockito.RETURNS_DEEP_STUBS);

    AbstractLightblueProxyServlet servlet =
        getTestServlet(mockHttpClient, null, "http://myservice.com", null);

    HttpServletRequest stubRequest =
        new StubHttpServletRequest(
            "http://my.site.com/app/get/the/thing?foo=bar",
            "GET",
            "{test:0}",
            "application/json",
            "/get/*");

    HttpServletResponse mockResponse = mock(HttpServletResponse.class);
    ServletOutputStream outputStream = new FakeServletOutputStream(new ByteArrayOutputStream());
    when(mockResponse.getOutputStream()).thenReturn(outputStream);

    servlet.service(stubRequest, mockResponse);

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

    verify(mockHttpClient).execute(requestCaptor.capture());

    HttpUriRequest request = requestCaptor.getValue();

    assertEquals("GET", request.getMethod());
    assertEquals(new URI("http://myservice.com/the/thing?foo=bar"), request.getURI());
    assertThat(request, instanceOf(HttpEntityEnclosingRequest.class));
    assertEquals(1, request.getHeaders("content-type").length);
    assertEquals("application/json", request.getHeaders("content-type")[0].getValue());

    HttpEntityEnclosingRequest entityEnclosingRequest = (HttpEntityEnclosingRequest) request;
    ByteArrayOutputStream entityOutStream = new ByteArrayOutputStream();
    entityEnclosingRequest.getEntity().writeTo(entityOutStream);

    byte[] expectedEntityBytes = new byte[stubRequest.getContentLength()];
    stubRequest.getInputStream().read(expectedEntityBytes, 0, stubRequest.getContentLength());

    assertEquals(new String(expectedEntityBytes), entityOutStream.toString());
  }
  @Test
  public void shouldAlwaysRespondWithJsonType() throws ServletException, IOException {
    CloseableHttpClient mockHttpClient =
        mock(CloseableHttpClient.class, Mockito.RETURNS_DEEP_STUBS);

    AbstractLightblueProxyServlet servlet = getTestServlet(mockHttpClient, null, null, null);

    HttpServletRequest stubRequest =
        new StubHttpServletRequest(
            "http://test.com/servlet/file", "GET", "{test:0}", "application/json", "/servlet/*");

    HttpServletResponse mockResponse = mock(HttpServletResponse.class);
    ServletOutputStream outputStream = new FakeServletOutputStream(new ByteArrayOutputStream());
    when(mockResponse.getOutputStream()).thenReturn(outputStream);

    servlet.service(stubRequest, mockResponse);

    verify(mockResponse).setContentType("application/json");
  }
  @Test
  public void shouldRespondWithErrorWhenBadServiceUri() throws ServletException, IOException {
    CloseableHttpClient mockHttpClient =
        mock(CloseableHttpClient.class, Mockito.RETURNS_DEEP_STUBS);

    AbstractLightblueProxyServlet servlet =
        getTestServlet(mockHttpClient, null, "bad service uri", null);

    HttpServletRequest stubRequest =
        new StubHttpServletRequest(
            "http://my.site.com/app", "GET", "{test:0}", "application/json", "/app/*");

    HttpServletResponse mockResponse = mock(HttpServletResponse.class);
    ServletOutputStream outputStream = new FakeServletOutputStream(new ByteArrayOutputStream());
    when(mockResponse.getOutputStream()).thenReturn(outputStream);

    servlet.service(stubRequest, mockResponse);

    String expectedError = "{\"error\":\"There was a problem calling the lightblue service\"}";

    assertEquals(expectedError, mockResponse.getOutputStream().toString());
  }