content: package ro.isdc.wro.http.handler;
  
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.assertFalse;
  import static org.junit.Assert.assertTrue;
  import static org.mockito.Matchers.anyString;
  import static org.mockito.Mockito.times;
  import static org.mockito.Mockito.verify;
  import static org.mockito.Mockito.when;
  
  import java.io.ByteArrayOutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.util.Date;
  
  import javax.servlet.FilterConfig;
  import javax.servlet.ServletContext;
  import javax.servlet.ServletOutputStream;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  
  import org.apache.commons.io.IOUtils;
  import org.junit.After;
  import org.junit.AfterClass;
  import org.junit.Before;
  import org.junit.BeforeClass;
  import org.junit.Test;
  import org.mockito.InjectMocks;
  import org.mockito.Mock;
  import org.mockito.Mockito;
  import org.mockito.MockitoAnnotations;
  import org.mockito.invocation.InvocationOnMock;
  import org.mockito.stubbing.Answer;
  
  import ro.isdc.wro.config.Context;
  import ro.isdc.wro.http.support.HttpHeader;
  import ro.isdc.wro.http.support.UnauthorizedRequestException;
  import ro.isdc.wro.manager.factory.BaseWroManagerFactory;
  import ro.isdc.wro.model.group.processor.Injector;
  import ro.isdc.wro.model.group.processor.InjectorBuilder;
  import ro.isdc.wro.model.resource.locator.ClasspathUriLocator;
  import ro.isdc.wro.model.resource.locator.UriLocator;
  import ro.isdc.wro.model.resource.locator.factory.UriLocatorFactory;
  import ro.isdc.wro.model.resource.support.ResourceAuthorizationManager;
  import ro.isdc.wro.util.WroUtil;
  
  
  /**
   * @author Ivar Conradi Østhus
   */
  public class TestResourceProxyRequestHandler {
    @InjectMocks
    private ResourceProxyRequestHandler victim;
    @Mock
    private HttpServletRequest request;
    @Mock
    private HttpServletResponse response;
    @Mock
    private ServletContext servletContext;
    @Mock
    private FilterConfig filterConfig;
    @Mock
    private ResourceAuthorizationManager mockAuthorizationManager;
    @Mock
    private UriLocatorFactory mockUriLocatorFactory;
    @Mock
    private UriLocator mockUriLocator;
  
    private OutputStream outputStream;
  
    private ServletOutputStream servletOutputStream;
  
    private String packagePath;
  
    @BeforeClass
    public static void onBeforeClass() {
      assertEquals(0, Context.countActive());
    }
  
    @AfterClass
    public static void onAfterClass() {
      assertEquals(0, Context.countActive());
    }
  
    @Before
    public void setup()
        throws IOException {
      MockitoAnnotations.initMocks(this);
      victim = new ResourceProxyRequestHandler();
  
      Mockito.when(filterConfig.getServletContext()).thenReturn(servletContext);
      Context.set(Context.webContext(request, response, filterConfig));
      // a more elaborate way to build injector, used to instruct it use a different instance of authorizationManager
      final Injector injector = new InjectorBuilder(new BaseWroManagerFactory().setUriLocatorFactory(
          mockUriLocatorFactory).setResourceAuthorizationManager(mockAuthorizationManager)).build();
      injector.inject(victim);
  
      when(mockUriLocatorFactory.getInstance(anyString())).thenReturn(mockUriLocator);
      when(mockUriLocatorFactory.locate(anyString())).then(new Answer<InputStream>() {
        public InputStream answer(final InvocationOnMock invocation)
            throws Throwable {
          final String uri = (String) invocation.getArguments()[0];
          return mockUriLocator.locate(uri);
        }
      });
      when(mockUriLocator.locate(anyString())).thenReturn(WroUtil.EMPTY_STREAM);
  
      packagePath = WroUtil.toPackageAsFolder(this.getClass());
  
      // Setup response writer
      outputStream = new ByteArrayOutputStream();
      servletOutputStream = new ServletOutputStream() {
        @Override
        public void write(final int i)
            throws IOException {
          outputStream.write(i);
        }
      };
      when(response.getOutputStream()).thenReturn(servletOutputStream);
    }
  
    @After
    public void tearDown() {
      Context.unset();
    }
  
    @Test
    public void shouldAlwaysBeEnabled() {
      assertTrue(victim.isEnabled());
    }
  
    @Test
    public void shouldAcceptCallsTo_wroResources() {
      when(request.getRequestURI()).thenReturn("?wroAPI=wroResources&id=test.css");
      when(request.getParameter(ResourceProxyRequestHandler.PATH_API)).thenReturn(
          ResourceProxyRequestHandler.PATH_RESOURCES);
      when(request.getParameter(ResourceProxyRequestHandler.PARAM_RESOURCE_ID)).thenReturn("test.css");
      assertTrue(victim.accept(request));
    }
  
    @Test
    public void shouldNotAcceptCallsTo_OtherUris() {
      when(request.getRequestURI()).thenReturn("/wro/someOtherUri");
      assertFalse(victim.accept(request));
    }
  
    @Test
    public void shouldReturnClasspathResource()
        throws IOException {
      final String resourceUri = "classpath:" + packagePath + "/" + "test.css";
      when(mockAuthorizationManager.isAuthorized(resourceUri)).thenReturn(true);
      when(request.getParameter(ResourceProxyRequestHandler.PARAM_RESOURCE_ID)).thenReturn(resourceUri);
      when(mockUriLocator.locate(anyString())).thenReturn(new ClasspathUriLocator().locate(resourceUri));
  
      victim.handle(request, response);
  
      final String body = outputStream.toString();
      final String expectedBody = IOUtils.toString(getInputStream("test.css"));
  
      assertEquals(expectedBody, body);
    }
  
    @Test(expected = UnauthorizedRequestException.class)
    public void cannotProxyUnauthorizedResources()
        throws IOException {
      final String resourceUri = "classpath:" + packagePath + "/" + "test.css";
      when(mockAuthorizationManager.isAuthorized(resourceUri)).thenReturn(false);
      when(request.getParameter(ResourceProxyRequestHandler.PARAM_RESOURCE_ID)).thenReturn(resourceUri);
      when(mockUriLocator.locate(anyString())).thenReturn(new ClasspathUriLocator().locate(resourceUri));
  
      victim.handle(request, response);
    }
  
    @Test
    public void shouldReturnRelativeResource()
        throws IOException {
      final String resourceUri = "/" + packagePath + "/" + "test.css";
      when(mockAuthorizationManager.isAuthorized(resourceUri)).thenReturn(true);
  
      // Set up victim
      when(mockUriLocator.locate(resourceUri)).thenReturn(getInputStream("test.css"));
      when(request.getParameter(ResourceProxyRequestHandler.PARAM_RESOURCE_ID)).thenReturn(resourceUri);
  
      // Perform Action
      victim.handle(request, response);
      final String body = outputStream.toString();
      final String expectedBody = IOUtils.toString(getInputStream("test.css"));
  
      verify(mockUriLocator, times(1)).locate(resourceUri);
      assertEquals(expectedBody, body);
    }
  
    @Test
    public void shouldSetResponseLength()
        throws IOException {
      final String resourceUri = "classpath:" + packagePath + "/" + "test.css";
      when(mockAuthorizationManager.isAuthorized(resourceUri)).thenReturn(true);
      when(request.getParameter(ResourceProxyRequestHandler.PARAM_RESOURCE_ID)).thenReturn(resourceUri);
      when(mockUriLocator.locate(anyString())).thenReturn(new ClasspathUriLocator().locate(resourceUri));
  
      victim.handle(request, response);
      final int expectedLength = IOUtils.toString(getInputStream("test.css")).length();
  
      verify(response, times(1)).setContentLength(expectedLength);
    }
  
    @Test
    public void shouldSetCSSContentType()
        throws IOException {
      final String resourceUri = "classpath:" + packagePath + "/" + "test.css";
      when(mockAuthorizationManager.isAuthorized(resourceUri)).thenReturn(true);
      when(request.getParameter(ResourceProxyRequestHandler.PARAM_RESOURCE_ID)).thenReturn(resourceUri);
  
      victim.handle(request, response);
  
      verify(response, times(1)).setContentType("text/css; charset=UTF-8");
    }
  
    @Test
    public void shouldSetJSContentType()
        throws IOException {
      final String resourceUri = "classpath:" + packagePath + "/" + "test.js";
      when(mockAuthorizationManager.isAuthorized(resourceUri)).thenReturn(true);
      when(request.getParameter(ResourceProxyRequestHandler.PARAM_RESOURCE_ID)).thenReturn(resourceUri);
  
      victim.handle(request, response);
  
      verify(response, times(1)).setContentType("application/javascript; charset=UTF-8");
    }
  
    @Test
    public void shouldSetPNGContentType()
        throws IOException {
      final String resourceUri = "classpath:" + packagePath + "/" + "test.png";
      when(mockAuthorizationManager.isAuthorized(resourceUri)).thenReturn(true);
      when(request.getParameter(ResourceProxyRequestHandler.PARAM_RESOURCE_ID)).thenReturn(resourceUri);
  
      victim.handle(request, response);
  
      verify(response, times(1)).setContentType("image/png");
    }
  
    @Test
    public void shouldSetCorrectResopnsCodeBasedOnResourceChangeState()
        throws IOException {
      final String resourceUri = "classpath:" + packagePath + "/" + "test.css";
      when(mockAuthorizationManager.isAuthorized(resourceUri)).thenReturn(true);
      when(request.getParameter(ResourceProxyRequestHandler.PARAM_RESOURCE_ID)).thenReturn(resourceUri);
  
      final long timeInFuture = new Date().getTime() + 10000;
      when(request.getDateHeader(HttpHeader.IF_MODIFIED_SINCE.toString())).thenReturn(timeInFuture);
      victim.handle(request, response);
      verify(response).setStatus(HttpServletResponse.SC_NOT_MODIFIED);
  
      final long longTimeAgo = 123L;
      when(request.getDateHeader(HttpHeader.IF_MODIFIED_SINCE.toString())).thenReturn(longTimeAgo);
      victim.handle(request, response);
      verify(response).setStatus(Mockito.eq(HttpServletResponse.SC_OK));
    }
  
    @Test
    public void shouldAssumeResourceChangedWhenModifiedSinceHeaderExtractionFails()
        throws Exception {
      final String resourceUri = "classpath:" + packagePath + "/" + "test.css";
      when(mockAuthorizationManager.isAuthorized(resourceUri)).thenReturn(true);
      when(request.getParameter(ResourceProxyRequestHandler.PARAM_RESOURCE_ID)).thenReturn(resourceUri);
  
      when(request.getDateHeader(HttpHeader.IF_MODIFIED_SINCE.toString())).thenThrow(
          new IllegalArgumentException("BOOM!"));
      victim.handle(request, response);
      verify(response).setStatus(HttpServletResponse.SC_OK);
    }
  
    private InputStream getInputStream(final String filename)
        throws IOException {
      return this.getClass().getClassLoader().getResourceAsStream(packagePath + "/" + filename);
    }
  
    @Test(expected = NullPointerException.class)
    public void cannotAcceptNullRequestUriToCreateProxyPath() {
      ResourceProxyRequestHandler.createProxyPath(null, "");
    }
  
    @Test
    public void shouldCreateProxyPath() {
      assertEquals("/wro/all.js?wroAPI=wroResources&id=id", ResourceProxyRequestHandler.createProxyPath("/wro/all.js", "id"));
      assertEquals("?wroAPI=wroResources&id=id", ResourceProxyRequestHandler.createProxyPath("", "id"));
    }
  
    @Test
    public void shouldDetectProxyUri() {
      assertTrue(ResourceProxyRequestHandler.isProxyUri("/path?wroAPI=wroResources&id=id"));
    }
  }
  