/**
* Copyright (C) 2012-2017 the original author or authors.
*
* 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 ninja.utils;
import com.google.common.collect.Maps;
import java.util.HashSet;
import java.util.Map;
import ninja.ContentTypes;
import ninja.Context;
import ninja.Cookie;
import ninja.Result;
import ninja.Results;
import ninja.Route;
import ninja.bodyparser.BodyParserEngine;
import ninja.bodyparser.BodyParserEngineManager;
import ninja.params.ParamParser;
import ninja.params.ParamParsers;
import ninja.session.FlashScope;
import ninja.session.Session;
import ninja.validation.Validation;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Matchers;
import org.mockito.Mock;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class AbstractContextTest {
@Mock
private Session sessionCookie;
@Mock
private FlashScope flashCookie;
@Mock
private BodyParserEngineManager bodyParserEngineManager;
@Mock
private Route route;
@Mock
private Validation validation;
@Mock
private BodyParserEngine bodyParserEngine;
@Mock
private NinjaProperties ninjaProperties;
private AbstractContextImpl abstractContext;
@Before
public void setUp() {
abstractContext = new AbstractContextImpl(
bodyParserEngineManager,
flashCookie,
ninjaProperties,
sessionCookie,
validation,
null,
new ParamParsers(new HashSet<ParamParser>()));
abstractContext.init("", "/");
}
@Test
public void getRemoteAddr() {
AbstractContextImpl context = spy(abstractContext);
doReturn("1.1.1.1").when(context).getRealRemoteAddr();
assertThat(context.getRemoteAddr(), is("1.1.1.1"));
}
@Test
public void getRemoteAddrIgnoresXForwardHeader() {
AbstractContextImpl context = spy(abstractContext);
when(ninjaProperties.getBooleanWithDefault(Context.NINJA_PROPERTIES_X_FORWARDED_FOR, false)).thenReturn(Boolean.FALSE);
doReturn("1.1.1.1").when(context).getRealRemoteAddr();
doReturn("2.2.2.2").when(context).getHeader(Context.X_FORWARD_HEADER);
assertThat(context.getRemoteAddr(), is("1.1.1.1"));
}
@Test
public void getRemoteAddrUsesXForwardHeader() {
AbstractContextImpl context = spy(abstractContext);
when(ninjaProperties.getBooleanWithDefault(Context.NINJA_PROPERTIES_X_FORWARDED_FOR, false)).thenReturn(Boolean.TRUE);
doReturn("1.1.1.1").when(context).getRealRemoteAddr();
doReturn("2.2.2.2").when(context).getHeader(Context.X_FORWARD_HEADER);
assertThat(context.getRemoteAddr(), is("2.2.2.2"));
}
@Test
public void getRemoteAddrParsesXForwardedForIfMoreThanOneHostPresent() {
AbstractContextImpl context = spy(abstractContext);
when(ninjaProperties.getBooleanWithDefault(Context.NINJA_PROPERTIES_X_FORWARDED_FOR, false)).thenReturn(Boolean.TRUE);
doReturn("1.1.1.1").when(context).getRealRemoteAddr();
doReturn("192.168.1.1, 192.168.1.2, 192.168.1.3").when(context).getHeader(Context.X_FORWARD_HEADER);
//make sure this is correct
assertThat(context.getRemoteAddr(), is("192.168.1.1"));
}
@Test
public void getRemoteAddrUsesFallbackIfXForwardedForIsNotValidInetAddr() {
AbstractContextImpl context = spy(abstractContext);
when(ninjaProperties.getBooleanWithDefault(Context.NINJA_PROPERTIES_X_FORWARDED_FOR, false)).thenReturn(Boolean.TRUE);
doReturn("1.1.1.1").when(context).getRealRemoteAddr();
doReturn("I_AM_NOT_A_VALID_ADDRESS").when(context).getHeader(Context.X_FORWARD_HEADER);
assertThat(context.getRemoteAddr(), is("1.1.1.1"));
}
@Test
public void addCookieViaResult() {
AbstractContextImpl context = spy(abstractContext);
Cookie cookie0 = Cookie.builder("cookie0", "yum0").setDomain("domain").build();
Cookie cookie1 = Cookie.builder("cookie1", "yum1").setDomain("domain").build();
// adding a cookie in the result will eventually trigger addCookie()...
Result result = Results.html();
result.addCookie(cookie0);
result.addCookie(cookie1);
doNothing().when(context).addCookie(cookie0);
doNothing().when(context).addCookie(cookie1);
// finalize the headers => the cookies must be copied over to the servletcookies
context.finalizeHeaders(result);
verify(context, times(1)).addCookie(cookie0);
verify(context, times(1)).addCookie(cookie1);
}
@Test
public void unsetCookieAddsCookieWithMaxAgeZero() {
AbstractContextImpl context = spy(abstractContext);
Cookie cookie = Cookie.builder("cookie", "yummy").setDomain("domain").build();
ArgumentCaptor<Cookie> argument = ArgumentCaptor.forClass(Cookie.class);
doNothing().when(context).addCookie(argument.capture());
context.unsetCookie(cookie);
assertThat(argument.getValue().getMaxAge(), is(0));
}
@Test
public void getPathParameter() {
AbstractContextImpl context = spy(abstractContext);
//mock a parametermap:
Map<String, String> parameterMap = Maps.newHashMap();
parameterMap.put("parameter", "parameter");
//and return the parameter map when any parameter is called...
when(route.getPathParametersEncoded(Matchers.anyString())).thenReturn(parameterMap);
context.setRoute(route);
// this parameter is not there and must return null
assertEquals(null, context.getPathParameter("parameter_not_set"));
assertEquals("parameter", context.getPathParameter("parameter"));
}
@Test
public void getPathParameterDecodingWorks() {
AbstractContextImpl context = spy(abstractContext);
//mock a parametermap:
Map<String, String> parameterMap = Maps.newHashMap();
parameterMap.put("parameter", "blue%2Fred%3Fand+green%E2%82%AC%2f");
//and return the parameter map when any parameter is called...
when(route.getPathParametersEncoded(Matchers.anyString())).thenReturn(parameterMap);
context.setRoute(route);
//that is how the above parameter looks decoded correctly:
assertEquals("blue/red?and+green€/", context.getPathParameter("parameter"));
}
@Test
public void getPathParameterAsInteger() {
AbstractContextImpl context = spy(abstractContext);
//mock a parametermap:
Map<String, String> parameterMap = Maps.newHashMap();
parameterMap.put("parameter", "parameter");
//and return the parameter map when any parameter is called...
when(route.getPathParametersEncoded(Matchers.anyString())).thenReturn(parameterMap);
context.setRoute(route);
//this will not work and return null
assertEquals(null, context.getPathParameterAsInteger("parameter"));
//now set an integer into the parametermap:
parameterMap.put("parameter", "1");
//this will work and return 1
assertEquals(new Integer(1), context.getPathParameterAsInteger("parameter"));
}
@Test
public void getParameterAsInteger() {
AbstractContextImpl context = spy(abstractContext);
//this will not work and return null
doReturn(null).when(context).getParameter("key_not_there");
assertEquals(null, context.getParameterAsInteger("key_not_there"));
//this will return the default value:
doReturn(null).when(context).getParameter("key_not_there");
assertEquals(new Integer(100), context.getParameterAsInteger("key_not_there", 100));
//this will work as the value is there...
doReturn("1").when(context).getParameter("key");
assertEquals(new Integer(1), context.getParameterAsInteger("key"));
}
@Test
public void getParameterAs() {
AbstractContextImpl context = spy(abstractContext);
doReturn(null).when(context).getParameter("key");
doReturn("100").when(context).getParameter("key1");
doReturn("true").when(context).getParameter("key2");
doReturn("10.1").when(context).getParameter("key3");
doReturn("x").when(context).getParameter("key4");
//this will not work and return null
assertEquals(null, context.getParameterAs("key", Long.class));
assertEquals(new Integer(100), context.getParameterAs("key1", Integer.class));
assertEquals(new Long(100), context.getParameterAs("key1", Long.class));
assertEquals(Boolean.TRUE, context.getParameterAs("key2", Boolean.class));
assertEquals(new Float(10.1), context.getParameterAs("key3", Float.class));
assertEquals(new Character('x'), context.getParameterAs("key4", Character.class));
}
@Test
public void finalizeInAbstractContextSavesFlashSessionCookies() {
AbstractContextImpl context = spy(abstractContext);
Result result = Results.json();
Cookie cookie = Cookie.builder("TEST", "value").build();
result.addCookie(cookie);
doNothing().when(context).addCookie(cookie);
ResponseStreams streams = context.finalizeHeaders(result);
// abstract finalizeHeaders does not return anything
assertThat(streams, is(nullValue()));
verify(flashCookie, times(1)).save(context);
verify(sessionCookie, times(1)).save(context);
verify(context, times(1)).addCookie(cookie);
}
@Test
public void getAcceptContentType() {
AbstractContextImpl context = spy(abstractContext);
doReturn(null).when(context).getHeader("accept");
assertEquals(Result.TEXT_HTML, context.getAcceptContentType());
doReturn("").when(context).getHeader("accept");
assertEquals(Result.TEXT_HTML, context.getAcceptContentType());
doReturn("totally_unknown").when(context).getHeader("accept");
assertEquals(Result.TEXT_HTML, context.getAcceptContentType());
doReturn("application/json").when(context).getHeader("accept");
assertEquals(Result.APPLICATION_JSON, context.getAcceptContentType());
doReturn("text/html, application/json").when(context).getHeader("accept");
assertEquals(Result.TEXT_HTML, context.getAcceptContentType());
doReturn("application/xhtml, application/json").when(context).getHeader("accept");
assertEquals(Result.TEXT_HTML, context.getAcceptContentType());
doReturn("text/plain").when(context).getHeader("accept");
assertEquals(Result.TEXT_PLAIN, context.getAcceptContentType());
doReturn("text/plain, application/json").when(context).getHeader("accept");
assertEquals(Result.APPLICATION_JSON, context.getAcceptContentType());
}
@Test
public void getAcceptEncoding() {
AbstractContextImpl context = spy(abstractContext);
String encoding = "compress, gzip";
doReturn(encoding).when(context).getHeader("accept-encoding");
assertEquals(encoding, context.getAcceptEncoding());
encoding = null;
doReturn(encoding).when(context).getHeader("accept-encoding");
assertNull(context.getAcceptEncoding());
encoding = "gzip;q=1.0, identity; q=0.5, *;q=0";
doReturn(encoding).when(context).getHeader("accept-encoding");
assertEquals(encoding, context.getAcceptEncoding());
}
@Test
public void getAcceptLanguage() {
AbstractContextImpl context = spy(abstractContext);
String language = "de";
doReturn(language).when(context).getHeader("accept-language");
assertEquals(language, context.getAcceptLanguage());
language = null;
doReturn(language).when(context).getHeader("accept-language");
assertNull(context.getAcceptLanguage());
language = "da, en-gb;q=0.8, en;q=0.7";
doReturn(language).when(context).getHeader("accept-language");
assertEquals(language, context.getAcceptLanguage());
}
@Test
public void getAcceptCharset() {
AbstractContextImpl context = spy(abstractContext);
String charset = "UTF-8";
doReturn(charset).when(context).getHeader("accept-charset");
assertEquals(charset, context.getAcceptCharset());
charset = null;
doReturn(charset).when(context).getHeader("accept-charset");
assertNull(context.getAcceptCharset());
charset = "iso-8859-5, unicode-1-1;q=0.8";
doReturn(charset).when(context).getHeader("accept-charset");
assertEquals(charset, context.getAcceptCharset());
}
static public class Dummy {
String name;
Long count;
}
@Test
public void testParseBodyJsonWorks() {
AbstractContextImpl context = spy(abstractContext);
doReturn("application/json; charset=utf-8").when(context).getRequestContentType();
when(bodyParserEngineManager.getBodyParserEngineForContentType("application/json")).thenReturn(bodyParserEngine);
when(bodyParserEngine.invoke(context, Dummy.class)).thenReturn(new Dummy());
Object o = context.parseBody(Dummy.class);
verify(bodyParserEngineManager).getBodyParserEngineForContentType("application/json");
assertTrue(o instanceof Dummy);
}
@Test
public void testParseBodyPostWorks() {
AbstractContextImpl context = spy(abstractContext);
doReturn(ContentTypes.APPLICATION_POST_FORM).when(context).getRequestContentType();
when(bodyParserEngineManager.getBodyParserEngineForContentType(ContentTypes.APPLICATION_POST_FORM)).thenReturn(bodyParserEngine);
Dummy dummy = new Dummy();
dummy.name = "post";
dummy.count = 245L;
when(bodyParserEngine.invoke(context, Dummy.class)).thenReturn(dummy);
Dummy o = context.parseBody(Dummy.class);
verify(bodyParserEngineManager).getBodyParserEngineForContentType(ContentTypes.APPLICATION_POST_FORM);
assertTrue(o instanceof Dummy);
assertTrue(o.name.equals(dummy.name));
assertTrue(o.count.equals(dummy.count));
}
@Test
public void testIsJsonWorks() {
AbstractContextImpl context = spy(abstractContext);
doReturn(ContentTypes.APPLICATION_JSON).when(context).getRequestContentType();
assertTrue(context.isRequestJson());
}
@Test
public void testIsXmlWorks() {
AbstractContextImpl context = spy(abstractContext);
doReturn(ContentTypes.APPLICATION_XML).when(context).getRequestContentType();
assertTrue(context.isRequestXml());
}
@Test
public void testParseBodyXmlWorks() {
AbstractContextImpl context = spy(abstractContext);
doReturn(ContentTypes.APPLICATION_XML).when(context).getRequestContentType();
when(bodyParserEngineManager.getBodyParserEngineForContentType("application/xml")).thenReturn(bodyParserEngine);
when(bodyParserEngine.invoke(context, Dummy.class)).thenReturn(new Dummy());
Object o = context.parseBody(Dummy.class);
verify(bodyParserEngineManager).getBodyParserEngineForContentType("application/xml");
assertTrue(o instanceof Dummy);
}
@Test
public void testParseBodyWithUnkownContentTypeWorks() {
AbstractContextImpl context = spy(abstractContext);
doReturn(null).when(context).getRequestContentType();
Object o = context.parseBody(Dummy.class);
assertNull(o);
}
@Test
public void testParseBodyWithUnknownRequestContentTypeWorks() {
AbstractContextImpl context = spy(abstractContext);
doReturn("application/UNKNOWN").when(context).getRequestContentType();
Object o = context.parseBody(Dummy.class);
assertNull(o);
}
}