// 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;
}
}