/* vim: set ts=2 et sw=2 cindent fo=qroca: */
package com.globant.katari.core.web;
import java.util.LinkedHashMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.junit.Before;
import org.junit.Test;
import org.junit.After;
import static org.junit.Assert.assertThat;
import static org.hamcrest.CoreMatchers.*;
import static org.easymock.EasyMock.*;
import com.globant.katari.tools.NanoHTTPD;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import javax.servlet.FilterChain;
import javax.servlet.http.Cookie;
public class ClusterNodeProxyFilterTest {
private NanoHTTPD server = null;
private ClusterNodeProxyFilter filter;
private Map<String, String> emptyNodeToUrl = new HashMap<String, String>();
private Map<String, String> nodeToUrl;
private MockHttpServletRequest request;
private MockHttpServletResponse response;
// A filter chain mock that expects a call to doFilter with request and
// response.
private FilterChain expectsDoFilterChain;
private FilterChain notCalledChain;
@Before public void setUp() throws Exception {
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
expectsDoFilterChain = createMock(FilterChain.class);
expectsDoFilterChain.doFilter(request, response);
replay(expectsDoFilterChain);
notCalledChain = createMock(FilterChain.class);
replay(notCalledChain);
server = new NanoHTTPD(0) {
public Response serve(final String uri, final String method, final
Properties headers, final Properties parameters) {
String result = new String(method + ": " + uri);
for (Object parameterName : parameters.keySet()) {
result = result + " p:" + parameterName + ": "
+ parameters.get(parameterName);
}
for (Object headerName : headers.keySet()) {
result = result + " h:" + headerName + ": "
+ headers.get(headerName);
}
return new NanoHTTPD.Response(NanoHTTPD.MIME_PLAINTEXT, result);
}
};
nodeToUrl = new LinkedHashMap<String, String>();
nodeToUrl.put("node-1", "http://localhost:" + server.getPort());
nodeToUrl.put("node-2", "http://host-2:8080");
}
@After public void tearDown() {
// We stop the server.
if (server != null) {
server.stop();
}
}
@Test (expected = IllegalArgumentException.class)
public void constructor_localForbidden() {
Map<String, String> nodeToUrl = new HashMap<String, String>();
nodeToUrl.put("local", "something");
filter = new ClusterNodeProxyFilter(nodeToUrl);
}
@Test (expected = IllegalArgumentException.class)
public void constructor_specialCharsForbidden() {
Map<String, String> nodeToUrl = new HashMap<String, String>();
nodeToUrl.put("l ocal", "something");
filter = new ClusterNodeProxyFilter(nodeToUrl);
}
@Test
public void doFilter_noNodes() throws Exception {
filter = new ClusterNodeProxyFilter(emptyNodeToUrl);
// No additional parameters.
filter.doFilter(request, response, expectsDoFilterChain);
verify(expectsDoFilterChain);
}
@Test
public void doFilter_noNodesWithParameter() throws Exception {
filter = new ClusterNodeProxyFilter(emptyNodeToUrl);
// The node parameter.
request.setParameter("katari-node", "some-node");
filter.doFilter(request, response, expectsDoFilterChain);
verify(expectsDoFilterChain);
}
@Test
public void doFilter_noNodesWithCookie() throws Exception {
filter = new ClusterNodeProxyFilter(emptyNodeToUrl);
// The node cookie.
request.setCookies(new Cookie("katari-node", "some-node"),
new Cookie("some-other-cookie", "value"));
filter.doFilter(request, response, expectsDoFilterChain);
verify(expectsDoFilterChain);
}
@Test
public void doFilter_listNodes() throws Exception {
filter = new ClusterNodeProxyFilter(nodeToUrl);
filter.doFilter(request, response, expectsDoFilterChain);
// It must not call chain.doFilter, just send a response body and a cookie.
Cookie katariNode = response.getCookie("katari-node");
assertThat(katariNode, is(not(nullValue())));
assertThat(katariNode.getMaxAge(), is(0));
assertThat(response.getContentAsString().matches(".*node-1.*node-2.*"),
is(true));
}
@Test
public void doFilter_toLocal() throws Exception {
filter = new ClusterNodeProxyFilter(nodeToUrl);
request.setParameter("katari-node", "local");
filter.doFilter(request, response, expectsDoFilterChain);
verify(expectsDoFilterChain);
}
@Test
public void doFilter_toProxy() throws Exception {
filter = new ClusterNodeProxyFilter(nodeToUrl);
request.setParameter("katari-node", "node-1");
request.setContent(new byte[0]);
request.setMethod("GET");
request.setRequestURI("/katari/module/a.do");
filter.doFilter(request, response, notCalledChain);
assertThat(response.getContentAsString().matches(
"^GET: /katari/module/a.do p:katari-node: local.*"), is(true));
verify(notCalledChain);
}
@Test
public void doFilter_toProxyWithParameters() throws Exception {
filter = new ClusterNodeProxyFilter(nodeToUrl);
request.setParameter("katari-node", "node-1");
request.setParameter("p1", "v1");
request.setContent(new byte[0]);
request.setMethod("POST");
request.setRequestURI("/katari/module/a.do");
request.addHeader("test", "test");
filter.doFilter(request, response, notCalledChain);
String content = response.getContentAsString();
assertThat(content.matches(
"^POST: /katari/module/a.do p:katari-node: local p:p1: v1.*"),
is(true));
assertThat(content.matches(".*h:test: test.*"), is(true));
verify(notCalledChain);
}
@Test
public void doFilter_toProxyWithPayload() throws Exception {
filter = new ClusterNodeProxyFilter(nodeToUrl);
request.setParameter("katari-node", "node-1");
request.setContent("test=value".getBytes("UTF-8"));
request.setMethod("POST");
request.setRequestURI("/katari/module/a.do");
filter.doFilter(request, response, notCalledChain);
String content = response.getContentAsString();
assertThat(content.matches(".*p:test: value.*"), is(true));
verify(notCalledChain);
}
}