// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package com.cloud.servlet; import java.io.File; import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.Matchers; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; public class StaticResourceServletTest { File rootDirectory; @Before public void setupFiles() throws IOException { rootDirectory = new File("target/tmp"); rootDirectory.mkdirs(); final File webInf = new File(rootDirectory, "WEB-INF"); webInf.mkdirs(); final File dir = new File(rootDirectory, "dir"); dir.mkdirs(); final File indexHtml = new File(rootDirectory, "index.html"); indexHtml.createNewFile(); FileUtils.writeStringToFile(indexHtml, "index.html"); final File defaultCss = new File(rootDirectory, "default.css"); defaultCss.createNewFile(); final File defaultCssGziped = new File(rootDirectory, "default.css.gz"); defaultCssGziped.createNewFile(); } @After public void cleanupFiles() { FileUtils.deleteQuietly(rootDirectory); } // negative tests @Test public void testNoSuchFile() throws ServletException, IOException { final StaticResourceServlet servlet = Mockito .mock(StaticResourceServlet.class); Mockito.doCallRealMethod() .when(servlet) .doGet(Matchers.any(HttpServletRequest.class), Matchers.any(HttpServletResponse.class)); final ServletContext servletContext = Mockito .mock(ServletContext.class); Mockito.when(servletContext.getRealPath("notexisting.css")).thenReturn( new File(rootDirectory, "notexisting.css").getAbsolutePath()); Mockito.when(servlet.getServletContext()).thenReturn(servletContext); final HttpServletRequest request = Mockito .mock(HttpServletRequest.class); Mockito.when(request.getServletPath()).thenReturn("notexisting.css"); final HttpServletResponse response = Mockito .mock(HttpServletResponse.class); servlet.doGet(request, response); Mockito.verify(response).setStatus(HttpServletResponse.SC_NOT_FOUND); } @Test public void testDirectory() throws ServletException, IOException { final HttpServletResponse response = doGetTest("dir"); Mockito.verify(response).setStatus(HttpServletResponse.SC_NOT_FOUND); } @Test public void testWebInf() throws ServletException, IOException { final HttpServletResponse response = doGetTest("WEB-INF/web.xml"); Mockito.verify(response).setStatus(HttpServletResponse.SC_NOT_FOUND); } // positive tests @Test public void testNotCompressedFile() throws ServletException, IOException { final HttpServletResponse response = doGetTest("index.html"); Mockito.verify(response).setStatus(HttpServletResponse.SC_OK); Mockito.verify(response).setContentType("text/html"); Mockito.verify(response, Mockito.times(0)).setHeader( "Content-Encoding", "gzip"); } @Test public void testCompressedFile() throws ServletException, IOException { final HashMap<String, String> headers = new HashMap<String, String>(); headers.put("Accept-Encoding", "gzip"); final HttpServletResponse response = doGetTest("default.css", headers); Mockito.verify(response).setStatus(HttpServletResponse.SC_OK); Mockito.verify(response).setContentType("text/css"); Mockito.verify(response, Mockito.times(1)).setHeader( "Content-Encoding", "gzip"); } @Test public void testCompressedFileWithoutBrowserSupport() throws ServletException, IOException { final HashMap<String, String> headers = new HashMap<String, String>(); headers.put("Accept-Encoding", ""); final HttpServletResponse response = doGetTest("default.css", headers); Mockito.verify(response).setStatus(HttpServletResponse.SC_OK); Mockito.verify(response).setContentType("text/css"); Mockito.verify(response, Mockito.times(0)).setHeader( "Content-Encoding", "gzip"); } @Test public void testWithEtag() throws ServletException, IOException { final HashMap<String, String> headers = new HashMap<String, String>(); headers.put("If-None-Match", StaticResourceServlet.getEtag(new File( rootDirectory, "default.css"))); final HttpServletResponse response = doGetTest("default.css", headers); Mockito.verify(response).setStatus(HttpServletResponse.SC_NOT_MODIFIED); } @Test public void testWithEtagOutdated() throws ServletException, IOException { final HashMap<String, String> headers = new HashMap<String, String>(); headers.put("If-None-Match", "NO-GOOD-ETAG"); final HttpServletResponse response = doGetTest("default.css", headers); Mockito.verify(response).setStatus(HttpServletResponse.SC_OK); } // utility methods @Test public void getEtag() { Assert.assertNotNull(StaticResourceServlet.getEtag(new File( rootDirectory, "index.html"))); } @Test public void getContentType() { Assert.assertEquals("text/plain", StaticResourceServlet.getContentType("foo.txt")); Assert.assertEquals("text/html", StaticResourceServlet.getContentType("index.html")); Assert.assertEquals("text/plain", StaticResourceServlet.getContentType("README.TXT")); } @Test public void isClientCompressionSupported() { final HttpServletRequest request = Mockito .mock(HttpServletRequest.class); Mockito.when(request.getHeader("Accept-Encoding")).thenReturn( "gzip, deflate"); Assert.assertTrue(StaticResourceServlet .isClientCompressionSupported(request)); } @Test public void isClientCompressionSupportedWithoutHeader() { final HttpServletRequest request = Mockito .mock(HttpServletRequest.class); Mockito.when(request.getHeader("Accept-Encoding")).thenReturn(null); Assert.assertFalse(StaticResourceServlet .isClientCompressionSupported(request)); } // test utilities private HttpServletResponse doGetTest(final String uri) throws ServletException, IOException { return doGetTest(uri, Collections.<String, String> emptyMap()); } private HttpServletResponse doGetTest(final String uri, final Map<String, String> headers) throws ServletException, IOException { final StaticResourceServlet servlet = Mockito .mock(StaticResourceServlet.class); Mockito.doCallRealMethod() .when(servlet) .doGet(Matchers.any(HttpServletRequest.class), Matchers.any(HttpServletResponse.class)); final ServletContext servletContext = Mockito .mock(ServletContext.class); Mockito.when(servletContext.getRealPath(uri)).thenReturn( new File(rootDirectory, uri).getAbsolutePath()); Mockito.when(servlet.getServletContext()).thenReturn(servletContext); final HttpServletRequest request = Mockito .mock(HttpServletRequest.class); Mockito.when(request.getServletPath()).thenReturn(uri); Mockito.when(request.getHeader(Matchers.anyString())).thenAnswer( new Answer<String>() { @Override public String answer(final InvocationOnMock invocation) throws Throwable { return headers.get(invocation.getArguments()[0]); } }); final HttpServletResponse response = Mockito .mock(HttpServletResponse.class); final ServletOutputStream responseBody = Mockito .mock(ServletOutputStream.class); Mockito.when(response.getOutputStream()).thenReturn(responseBody); servlet.doGet(request, response); return response; } }