Add fake HttpServlet{Request,Response} for testing

Instead of relying on mocks, provide mostly-featureful fakes that
allow inspection of the structured data passed to them. The fake
methods other than path getters are not really used yet.

These classes are largely copied from the Gitiles project at 4434b800;
the entirety of the copied code was authored by Google employees at
Google, so it is safe to include in this project.

Change-Id: I57af5d32cfabda6498744382100b4781e4f23d49
This commit is contained in:
Dave Borowitz
2015-12-01 12:12:51 -05:00
parent dbe169820d
commit 054b8f385f
7 changed files with 849 additions and 92 deletions

View File

@@ -58,6 +58,7 @@ java_test(
'//gerrit-reviewdb:server',
'//gerrit-server:server',
'//gerrit-util-http:http',
'//gerrit-util-http:testutil',
'//lib:junit',
'//lib:gson',
'//lib:gwtorm',

View File

@@ -22,6 +22,8 @@ import static org.easymock.EasyMock.newCapture;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.registration.ReloadableRegistrationHandle;
import com.google.gerrit.server.plugins.Plugin;
import com.google.gerrit.util.http.testutil.FakeHttpServletRequest;
import com.google.gerrit.util.http.testutil.FakeHttpServletResponse;
import com.google.inject.Key;
import com.google.inject.util.Providers;
@@ -88,8 +90,8 @@ public class AllRequestFilterFilterProxyTest {
EasyMockSupport ems = new EasyMockSupport();
FilterConfig config = ems.createMock(FilterConfig.class);
HttpServletRequest req = ems.createMock(HttpServletRequest.class);
HttpServletResponse res = ems.createMock(HttpServletResponse.class);
HttpServletRequest req = new FakeHttpServletRequest();
HttpServletResponse res = new FakeHttpServletResponse();
FilterChain chain = ems.createMock(FilterChain.class);
chain.doFilter(req, res);
@@ -110,8 +112,8 @@ public class AllRequestFilterFilterProxyTest {
EasyMockSupport ems = new EasyMockSupport();
FilterConfig config = ems.createMock("config", FilterConfig.class);
HttpServletRequest req = ems.createMock("req", HttpServletRequest.class);
HttpServletResponse res = ems.createMock("res", HttpServletResponse.class);
HttpServletRequest req = new FakeHttpServletRequest();
HttpServletResponse res = new FakeHttpServletResponse();
FilterChain chain = ems.createMock("chain", FilterChain.class);
@@ -137,8 +139,8 @@ public class AllRequestFilterFilterProxyTest {
EasyMockSupport ems = new EasyMockSupport();
FilterConfig config = ems.createMock(FilterConfig.class);
HttpServletRequest req = ems.createMock(HttpServletRequest.class);
HttpServletResponse res = ems.createMock(HttpServletResponse.class);
HttpServletRequest req = new FakeHttpServletRequest();
HttpServletResponse res = new FakeHttpServletResponse();
IMocksControl mockControl = ems.createStrictControl();
FilterChain chain = mockControl.createMock(FilterChain.class);
@@ -169,8 +171,8 @@ public class AllRequestFilterFilterProxyTest {
EasyMockSupport ems = new EasyMockSupport();
FilterConfig config = ems.createMock(FilterConfig.class);
HttpServletRequest req = ems.createMock(HttpServletRequest.class);
HttpServletResponse res = ems.createMock(HttpServletResponse.class);
HttpServletRequest req = new FakeHttpServletRequest();
HttpServletResponse res = new FakeHttpServletResponse();
IMocksControl mockControl = ems.createStrictControl();
FilterChain chain = mockControl.createMock(FilterChain.class);
@@ -202,8 +204,8 @@ public class AllRequestFilterFilterProxyTest {
EasyMockSupport ems = new EasyMockSupport();
FilterConfig config = ems.createMock(FilterConfig.class);
HttpServletRequest req = ems.createMock(HttpServletRequest.class);
HttpServletResponse res = ems.createMock(HttpServletResponse.class);
HttpServletRequest req = new FakeHttpServletRequest();
HttpServletResponse res = new FakeHttpServletResponse();
IMocksControl mockControl = ems.createStrictControl();
FilterChain chain = mockControl.createMock(FilterChain.class);
@@ -242,10 +244,10 @@ public class AllRequestFilterFilterProxyTest {
EasyMockSupport ems = new EasyMockSupport();
FilterConfig config = ems.createMock(FilterConfig.class);
HttpServletRequest req1 = ems.createMock("req1", HttpServletRequest.class);
HttpServletRequest req2 = ems.createMock("req2", HttpServletRequest.class);
HttpServletResponse res1 = ems.createMock("res1", HttpServletResponse.class);
HttpServletResponse res2 = ems.createMock("res2", HttpServletResponse.class);
HttpServletRequest req1 = new FakeHttpServletRequest();
HttpServletRequest req2 = new FakeHttpServletRequest();
HttpServletResponse res1 = new FakeHttpServletResponse();
HttpServletResponse res2 = new FakeHttpServletResponse();
IMocksControl mockControl = ems.createStrictControl();
FilterChain chain = mockControl.createMock("chain", FilterChain.class);
@@ -294,12 +296,12 @@ public class AllRequestFilterFilterProxyTest {
EasyMockSupport ems = new EasyMockSupport();
FilterConfig config = ems.createMock(FilterConfig.class);
HttpServletRequest req1 = ems.createMock("req1", HttpServletRequest.class);
HttpServletRequest req2 = ems.createMock("req2", HttpServletRequest.class);
HttpServletRequest req3 = ems.createMock("req3", HttpServletRequest.class);
HttpServletResponse res1 = ems.createMock("res1", HttpServletResponse.class);
HttpServletResponse res2 = ems.createMock("res2", HttpServletResponse.class);
HttpServletResponse res3 = ems.createMock("res3", HttpServletResponse.class);
HttpServletRequest req1 = new FakeHttpServletRequest();
HttpServletRequest req2 = new FakeHttpServletRequest();
HttpServletRequest req3 = new FakeHttpServletRequest();
HttpServletResponse res1 = new FakeHttpServletResponse();
HttpServletResponse res2 = new FakeHttpServletResponse();
HttpServletResponse res3 = new FakeHttpServletResponse();
Plugin plugin = ems.createMock(Plugin.class);

View File

@@ -14,10 +14,9 @@
package com.google.gerrit.httpd.plugins;
import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.junit.Assert.assertEquals;
import static com.google.common.truth.Truth.assertThat;
import com.google.gerrit.util.http.testutil.FakeHttpServletRequest;
import org.junit.Test;
@@ -34,16 +33,17 @@ public class ContextMapperTest {
ContextMapper classUnderTest = new ContextMapper(CONTEXT);
HttpServletRequest originalRequest =
createMockRequest("/plugins/", PLUGIN_NAME + "/" + RESOURCE);
createFakeRequest("/plugins/", PLUGIN_NAME + "/" + RESOURCE);
HttpServletRequest result =
classUnderTest.create(originalRequest, PLUGIN_NAME);
assertEquals(CONTEXT + "/plugins/" + PLUGIN_NAME, result.getContextPath());
assertEquals("", result.getServletPath());
assertEquals("/" + RESOURCE, result.getPathInfo());
assertEquals(CONTEXT + "/plugins/" + PLUGIN_NAME + "/" + RESOURCE,
result.getRequestURI());
assertThat(result.getContextPath())
.isEqualTo(CONTEXT + "/plugins/" + PLUGIN_NAME);
assertThat(result.getServletPath()).isEqualTo("");
assertThat(result.getPathInfo()).isEqualTo("/" + RESOURCE);
assertThat(result.getRequestURI())
.isEqualTo(CONTEXT + "/plugins/" + PLUGIN_NAME + "/" + RESOURCE);
}
@Test
@@ -51,29 +51,22 @@ public class ContextMapperTest {
ContextMapper classUnderTest = new ContextMapper(CONTEXT);
HttpServletRequest originalRequest =
createMockRequest("/a/plugins/", PLUGIN_NAME + "/" + RESOURCE);
createFakeRequest("/a/plugins/", PLUGIN_NAME + "/" + RESOURCE);
HttpServletRequest result =
classUnderTest.create(originalRequest, PLUGIN_NAME);
assertEquals(CONTEXT + "/a/plugins/" + PLUGIN_NAME,
result.getContextPath());
assertEquals("", result.getServletPath());
assertEquals("/" + RESOURCE, result.getPathInfo());
assertEquals(CONTEXT + "/a/plugins/" + PLUGIN_NAME + "/" + RESOURCE,
result.getRequestURI());
assertThat(result.getContextPath())
.isEqualTo(CONTEXT + "/a/plugins/" + PLUGIN_NAME);
assertThat(result.getServletPath()).isEqualTo("");
assertThat(result.getPathInfo()).isEqualTo("/" + RESOURCE);
assertThat(result.getRequestURI())
.isEqualTo(CONTEXT + "/a/plugins/" + PLUGIN_NAME + "/" + RESOURCE);
}
private static HttpServletRequest createMockRequest(String servletPath,
private static FakeHttpServletRequest createFakeRequest(String servletPath,
String pathInfo) {
HttpServletRequest req = createNiceMock(HttpServletRequest.class);
expect(req.getContextPath()).andStubReturn(CONTEXT);
expect(req.getServletPath()).andStubReturn(servletPath);
expect(req.getPathInfo()).andStubReturn(pathInfo);
String uri = CONTEXT + servletPath + pathInfo;
expect(req.getRequestURI()).andStubReturn(uri);
replay(req);
return req;
return new FakeHttpServletRequest(
"gerrit.example.com", 80, CONTEXT, servletPath).setPathInfo(pathInfo);
}
}

View File

@@ -5,11 +5,29 @@ java_library(
visibility = ['PUBLIC'],
)
TESTUTIL_SRCS = glob(['src/test/**/testutil/**/*.java'])
java_library(
name = 'testutil',
srcs = TESTUTIL_SRCS,
deps = [
'//gerrit-extension-api:api',
'//lib:guava',
'//lib:servlet-api-3_1',
'//lib/jgit:jgit',
],
visibility = ['PUBLIC'],
)
java_test(
name = 'http_tests',
srcs = glob(['src/test/java/**/*.java']),
srcs = glob(
['src/test/java/**/*.java'],
excludes = TESTUTIL_SRCS,
),
deps = [
':http',
':testutil',
'//lib:junit',
'//lib:servlet-api-3_1',
'//lib:truth',

View File

@@ -15,77 +15,50 @@
package com.google.gerrit.util.http;
import static com.google.common.truth.Truth.assertThat;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import org.junit.After;
import org.junit.Before;
import com.google.gerrit.util.http.testutil.FakeHttpServletRequest;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
public class RequestUtilTest {
private List<Object> mocks;
@Before
public void setUp() {
mocks = Collections.synchronizedList(new ArrayList<>());
}
@After
public void tearDown() {
for (Object mock : mocks) {
verify(mock);
}
}
@Test
public void emptyContextPath() {
assertThat(RequestUtil.getEncodedPathInfo(
mockRequest("/s/foo/bar", "", "/s"))).isEqualTo("/foo/bar");
fakeRequest("", "/s", "/foo/bar"))).isEqualTo("/foo/bar");
assertThat(RequestUtil.getEncodedPathInfo(
mockRequest("/s/foo%2Fbar", "", "/s"))).isEqualTo("/foo%2Fbar");
fakeRequest("", "/s", "/foo%2Fbar"))).isEqualTo("/foo%2Fbar");
}
@Test
public void emptyServletPath() {
assertThat(RequestUtil.getEncodedPathInfo(
mockRequest("/c/foo/bar", "", "/c"))).isEqualTo("/foo/bar");
fakeRequest("", "/c", "/foo/bar"))).isEqualTo("/foo/bar");
assertThat(RequestUtil.getEncodedPathInfo(
mockRequest("/c/foo%2Fbar", "", "/c"))).isEqualTo("/foo%2Fbar");
fakeRequest("", "/c", "/foo%2Fbar"))).isEqualTo("/foo%2Fbar");
}
@Test
public void trailingSlashes() {
assertThat(RequestUtil.getEncodedPathInfo(
mockRequest("/c/s/foo/bar/", "/c", "/s"))).isEqualTo("/foo/bar/");
fakeRequest("/c", "/s", "/foo/bar/"))).isEqualTo("/foo/bar/");
assertThat(RequestUtil.getEncodedPathInfo(
mockRequest("/c/s/foo/bar///", "/c", "/s"))).isEqualTo("/foo/bar/");
fakeRequest("/c", "/s", "/foo/bar///"))).isEqualTo("/foo/bar/");
assertThat(RequestUtil.getEncodedPathInfo(
mockRequest("/c/s/foo%2Fbar/", "/c", "/s"))).isEqualTo("/foo%2Fbar/");
fakeRequest("/c", "/s", "/foo%2Fbar/"))).isEqualTo("/foo%2Fbar/");
assertThat(RequestUtil.getEncodedPathInfo(
mockRequest("/c/s/foo%2Fbar///", "/c", "/s"))).isEqualTo("/foo%2Fbar/");
fakeRequest("/c", "/s", "/foo%2Fbar///"))).isEqualTo("/foo%2Fbar/");
}
@Test
public void servletPathMatchesRequestPath() {
public void emptyPathInfo() {
assertThat(RequestUtil.getEncodedPathInfo(
mockRequest("/c/s", "/c", "/s"))).isNull();
fakeRequest("/c", "/s", ""))).isNull();
}
private HttpServletRequest mockRequest(String uri, String contextPath, String servletPath) {
HttpServletRequest req = createMock(HttpServletRequest.class);
expect(req.getRequestURI()).andStubReturn(uri);
expect(req.getContextPath()).andStubReturn(contextPath);
expect(req.getServletPath()).andStubReturn(servletPath);
replay(req);
mocks.add(req);
return req;
private FakeHttpServletRequest fakeRequest(String contextPath,
String servletPath, String pathInfo) {
FakeHttpServletRequest req = new FakeHttpServletRequest(
"gerrit.example.com", 80, contextPath, servletPath);
return req.setPathInfo(pathInfo);
}
}

View File

@@ -0,0 +1,480 @@
// Copyright (C) 2015 The Android Open Source Project
//
// Licensed 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.google.gerrit.util.http.testutil;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.base.Function;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Maps;
import com.google.gerrit.extensions.restapi.Url;
import java.io.BufferedReader;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.Principal;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.servlet.AsyncContext;
import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpUpgradeHandler;
import javax.servlet.http.Part;
/** Simple fake implementation of {@link HttpServletRequest}. */
public class FakeHttpServletRequest implements HttpServletRequest {
public static final String SERVLET_PATH = "/b";
private final Map<String, Object> attributes;
private final ListMultimap<String, String> headers;
private ListMultimap<String, String> parameters;
private String hostName;
private int port;
private String contextPath;
private String servletPath;
private String path;
public FakeHttpServletRequest() {
this("gerrit.example.com", 80, "", SERVLET_PATH);
}
public FakeHttpServletRequest(String hostName, int port, String contextPath,
String servletPath) {
this.hostName = checkNotNull(hostName, "hostName");
checkArgument(port > 0);
this.port = port;
this.contextPath = checkNotNull(contextPath, "contextPath");
this.servletPath = checkNotNull(servletPath, "servletPath");
attributes = Maps.newConcurrentMap();
parameters = LinkedListMultimap.create();
headers = LinkedListMultimap.create();
}
@Override
public Object getAttribute(String name) {
return attributes.get(name);
}
@Override
public Enumeration<String> getAttributeNames() {
return Collections.enumeration(attributes.keySet());
}
@Override
public String getCharacterEncoding() {
return UTF_8.name();
}
@Override
public int getContentLength() {
return -1;
}
@Override
public String getContentType() {
return null;
}
@Override
public ServletInputStream getInputStream() {
throw new UnsupportedOperationException();
}
@Override
public String getLocalAddr() {
return "1.2.3.4";
}
@Override
public String getLocalName() {
return hostName;
}
@Override
public int getLocalPort() {
return port;
}
@Override
public Locale getLocale() {
return Locale.US;
}
@Override
public Enumeration<Locale> getLocales() {
return Collections.enumeration(Collections.singleton(Locale.US));
}
@Override
public String getParameter(String name) {
return Iterables.getFirst(parameters.get(name), null);
}
private static final Function<Collection<String>, String[]> STRING_COLLECTION_TO_ARRAY =
new Function<Collection<String>, String[]>() {
@Override
public String[] apply(Collection<String> values) {
return values.toArray(new String[0]);
}
};
@Override
public Map<String, String[]> getParameterMap() {
return Collections.unmodifiableMap(
Maps.transformValues(parameters.asMap(), STRING_COLLECTION_TO_ARRAY));
}
@Override
public Enumeration<String> getParameterNames() {
return Collections.enumeration(parameters.keySet());
}
@Override
public String[] getParameterValues(String name) {
return STRING_COLLECTION_TO_ARRAY.apply(parameters.get(name));
}
public void setQueryString(String qs) {
ListMultimap<String, String> params = LinkedListMultimap.create();
for (String entry : Splitter.on('&').split(qs)) {
List<String> kv = Splitter.on('=').limit(2).splitToList(entry);
try {
params.put(URLDecoder.decode(kv.get(0), UTF_8.name()),
kv.size() == 2 ? URLDecoder.decode(kv.get(1), UTF_8.name()) : "");
} catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException(e);
}
}
parameters = params;
}
@Override
public String getProtocol() {
return "HTTP/1.1";
}
@Override
public BufferedReader getReader() {
throw new UnsupportedOperationException();
}
@Override
@Deprecated
public String getRealPath(String path) {
throw new UnsupportedOperationException();
}
@Override
public String getRemoteAddr() {
return "5.6.7.8";
}
@Override
public String getRemoteHost() {
return "remotehost";
}
@Override
public int getRemotePort() {
return 1234;
}
@Override
public RequestDispatcher getRequestDispatcher(String path) {
throw new UnsupportedOperationException();
}
@Override
public String getScheme() {
return port == 443 ? "https" : "http";
}
@Override
public String getServerName() {
return hostName;
}
@Override
public int getServerPort() {
return port;
}
@Override
public boolean isSecure() {
return port == 443;
}
@Override
public void removeAttribute(String name) {
attributes.remove(name);
}
@Override
public void setAttribute(String name, Object value) {
attributes.put(name, value);
}
@Override
public void setCharacterEncoding(String env) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public String getAuthType() {
return null;
}
@Override
public String getContextPath() {
return contextPath;
}
@Override
public Cookie[] getCookies() {
return new Cookie[0];
}
@Override
public long getDateHeader(String name) {
throw new UnsupportedOperationException();
}
@Override
public String getHeader(String name) {
return Iterables.getFirst(headers.get(name), null);
}
@Override
public Enumeration<String> getHeaderNames() {
return Collections.enumeration(headers.keySet());
}
@Override
public Enumeration<String> getHeaders(String name) {
return Collections.enumeration(headers.get(name));
}
@Override
public int getIntHeader(String name) {
return Integer.parseInt(getHeader(name));
}
@Override
public String getMethod() {
return "GET";
}
@Override
public String getPathInfo() {
return path;
}
public FakeHttpServletRequest setPathInfo(String path) {
this.path = checkNotNull(path);
return this;
}
@Override
public String getPathTranslated() {
return path;
}
@Override
public String getQueryString() {
return paramsToString(parameters);
}
@Override
public String getRemoteUser() {
return null;
}
@Override
public String getRequestURI() {
String uri = contextPath + servletPath + path;
if (!parameters.isEmpty()) {
uri += "?" + paramsToString(parameters);
}
return uri;
}
@Override
public StringBuffer getRequestURL() {
return null;
}
@Override
public String getRequestedSessionId() {
return null;
}
@Override
public String getServletPath() {
return servletPath;
}
@Override
public HttpSession getSession() {
throw new UnsupportedOperationException();
}
@Override
public HttpSession getSession(boolean create) {
throw new UnsupportedOperationException();
}
@Override
public Principal getUserPrincipal() {
throw new UnsupportedOperationException();
}
@Override
public boolean isRequestedSessionIdFromCookie() {
throw new UnsupportedOperationException();
}
@Override
public boolean isRequestedSessionIdFromURL() {
throw new UnsupportedOperationException();
}
@Override
@Deprecated
public boolean isRequestedSessionIdFromUrl() {
throw new UnsupportedOperationException();
}
@Override
public boolean isRequestedSessionIdValid() {
throw new UnsupportedOperationException();
}
@Override
public boolean isUserInRole(String role) {
throw new UnsupportedOperationException();
}
private static String paramsToString(ListMultimap<String, String> params) {
StringBuilder sb = new StringBuilder();
boolean first = true;
for (Map.Entry<String, String> e : params.entries()) {
if (!first) {
sb.append('&');
} else {
first = false;
}
sb.append(Url.encode(e.getKey()));
if (!"".equals(e.getValue())) {
sb.append('=').append(Url.encode(e.getValue()));
}
}
return sb.toString();
}
@Override
public AsyncContext getAsyncContext() {
throw new UnsupportedOperationException();
}
@Override
public DispatcherType getDispatcherType() {
throw new UnsupportedOperationException();
}
@Override
public ServletContext getServletContext() {
throw new UnsupportedOperationException();
}
@Override
public boolean isAsyncStarted() {
return false;
}
@Override
public boolean isAsyncSupported() {
return false;
}
@Override
public AsyncContext startAsync() {
throw new UnsupportedOperationException();
}
@Override
public AsyncContext startAsync(ServletRequest req, ServletResponse res) {
throw new UnsupportedOperationException();
}
@Override
public boolean authenticate(HttpServletResponse res) {
throw new UnsupportedOperationException();
}
@Override
public Part getPart(String name) {
throw new UnsupportedOperationException();
}
@Override
public Collection<Part> getParts() {
throw new UnsupportedOperationException();
}
@Override
public void login(String username, String password) {
throw new UnsupportedOperationException();
}
@Override
public void logout() {
throw new UnsupportedOperationException();
}
@Override
public long getContentLengthLong() {
return getContentLength();
}
@Override
public String changeSessionId() {
throw new UnsupportedOperationException();
}
@Override
public <T extends HttpUpgradeHandler> T upgrade(
Class<T> httpUpgradeHandlerClass) {
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,290 @@
// Copyright (C) 2015 The Android Open Source Project
//
// Licensed 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.google.gerrit.util.http.testutil;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.collect.Iterables;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.net.HttpHeaders;
import org.eclipse.jgit.util.RawParseUtils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.Locale;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
/** Simple fake implementation of {@link HttpServletResponse}. */
public class FakeHttpServletResponse implements HttpServletResponse {
private final ByteArrayOutputStream actualBody = new ByteArrayOutputStream();
private final ListMultimap<String, String> headers = LinkedListMultimap.create();
private int status = SC_OK;
private boolean committed;
private ServletOutputStream outputStream;
private PrintWriter writer;
public FakeHttpServletResponse() {
}
@Override
public synchronized void flushBuffer() throws IOException {
if (outputStream != null) {
outputStream.flush();
}
if (writer != null) {
writer.flush();
}
}
@Override
public int getBufferSize() {
throw new UnsupportedOperationException();
}
@Override
public String getCharacterEncoding() {
return UTF_8.name();
}
@Override
public String getContentType() {
return null;
}
@Override
public Locale getLocale() {
return Locale.US;
}
@Override
public synchronized ServletOutputStream getOutputStream() {
checkState(writer == null, "getWriter() already called");
if (outputStream == null) {
final PrintWriter osWriter = new PrintWriter(actualBody);
outputStream = new ServletOutputStream() {
@Override
public void write(int c) throws IOException {
osWriter.write(c);
osWriter.flush();
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setWriteListener(WriteListener listener) {
throw new UnsupportedOperationException();
}
};
}
return outputStream;
}
@Override
public synchronized PrintWriter getWriter() {
checkState(outputStream == null, "getOutputStream() already called");
if (writer == null) {
writer = new PrintWriter(actualBody);
}
return writer;
}
@Override
public synchronized boolean isCommitted() {
return committed;
}
@Override
public void reset() {
throw new UnsupportedOperationException();
}
@Override
public void resetBuffer() {
throw new UnsupportedOperationException();
}
@Override
public void setBufferSize(int sz) {
throw new UnsupportedOperationException();
}
@Override
public void setCharacterEncoding(String name) {
checkArgument(UTF_8.equals(Charset.forName(name)),
"unsupported charset: %s", name);
}
@Override
public void setContentLength(int length) {
setContentLengthLong(length);
}
@Override
public void setContentLengthLong(long length) {
headers.removeAll(HttpHeaders.CONTENT_LENGTH);
headers.put(HttpHeaders.CONTENT_LENGTH, Long.toString(length));
}
@Override
public void setContentType(String type) {
headers.removeAll(HttpHeaders.CONTENT_TYPE);
headers.put(HttpHeaders.CONTENT_TYPE, type);
}
@Override
public void setLocale(Locale locale) {
throw new UnsupportedOperationException();
}
@Override
public void addCookie(Cookie cookie) {
throw new UnsupportedOperationException();
}
@Override
public void addDateHeader(String name, long value) {
throw new UnsupportedOperationException();
}
@Override
public void addHeader(String name, String value) {
headers.put(name, value);
}
@Override
public void addIntHeader(String name, int value) {
headers.put(name, Integer.toString(value));
}
@Override
public boolean containsHeader(String name) {
return headers.containsKey(name);
}
@Override
public String encodeRedirectURL(String url) {
throw new UnsupportedOperationException();
}
@Override
@Deprecated
public String encodeRedirectUrl(String url) {
throw new UnsupportedOperationException();
}
@Override
public String encodeURL(String url) {
throw new UnsupportedOperationException();
}
@Override
@Deprecated
public String encodeUrl(String url) {
throw new UnsupportedOperationException();
}
@Override
public synchronized void sendError(int sc) {
status = sc;
committed = true;
}
@Override
public synchronized void sendError(int sc, String msg) {
status = sc;
committed = true;
}
@Override
public synchronized void sendRedirect(String loc) {
status = SC_FOUND;
setHeader(HttpHeaders.LOCATION, loc);
committed = true;
}
@Override
public void setDateHeader(String name, long value) {
setHeader(name, Long.toString(value));
}
@Override
public void setHeader(String name, String value) {
headers.removeAll(name);
addHeader(name, value);
}
@Override
public void setIntHeader(String name, int value) {
headers.removeAll(name);
addIntHeader(name, value);
}
@Override
public synchronized void setStatus(int sc) {
status = sc;
committed = true;
}
@Override
@Deprecated
public synchronized void setStatus(int sc, String msg) {
status = sc;
committed = true;
}
@Override
public synchronized int getStatus() {
return status;
}
@Override
public String getHeader(String name) {
return Iterables.getFirst(headers.get(checkNotNull(name)), null);
}
@Override
public Collection<String> getHeaderNames() {
return headers.keySet();
}
@Override
public Collection<String> getHeaders(String name) {
return headers.get(checkNotNull(name));
}
public byte[] getActualBody() {
return actualBody.toByteArray();
}
public String getActualBodyString() {
return RawParseUtils.decode(getActualBody());
}
}