/*
* #%L
* Wisdom-Framework
* %%
* Copyright (C) 2013 - 2014 Wisdom Framework
* %%
* 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.
* #L%
*/
package org.wisdom.error;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableList;
import org.junit.After;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.wisdom.api.Controller;
import org.wisdom.api.DefaultController;
import org.wisdom.api.configuration.ApplicationConfiguration;
import org.wisdom.api.content.Json;
import org.wisdom.api.exceptions.ExceptionMapper;
import org.wisdom.api.exceptions.HttpException;
import org.wisdom.api.http.*;
import org.wisdom.api.interception.Filter;
import org.wisdom.api.interception.Interceptor;
import org.wisdom.api.interception.RequestContext;
import org.wisdom.api.router.Route;
import org.wisdom.api.router.Router;
import org.wisdom.api.templates.Template;
import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.NoSuchElementException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Check the behavior of the default page error handler.
*/
public class DefaultPageErrorHandlerTest {
@Test
public void testStackTraceCleanup() throws Exception {
StackTraceElement[] stack = ImmutableList.of(
new StackTraceElement("org.wisdom.samples.error.ErroneousController", "__M_doSomethingWrong",
"ErroneousController.java", 36),
new StackTraceElement("org.wisdom.samples.error.ErroneousController", "doSomethingWrong",
"ErroneousController.java", -1)
).toArray(new StackTraceElement[2]);
List<StackTraceElement> cleanup = StackTraceUtils.cleanup(stack);
assertThat(cleanup).hasSize(1);
assertThat(cleanup.get(0).getMethodName()).isEqualTo(stack[1].getMethodName());
}
@Test
public void testUri() throws Exception {
DefaultPageErrorHandler handler = new DefaultPageErrorHandler();
assertThat(handler.uri().matcher("/").matches()).isTrue();
assertThat(handler.uri().matcher("/foo").matches()).isTrue();
}
@Test
public void testPriority() throws Exception {
DefaultPageErrorHandler handler = new DefaultPageErrorHandler();
assertThat(handler.priority()).isGreaterThan(0);
}
@Test
public void switchToHeadWhenGetRouteExist() throws Exception {
DefaultPageErrorHandler handler = new DefaultPageErrorHandler();
handler.router = mock(Router.class);
handler.configuration = mock(ApplicationConfiguration.class);
when(handler.configuration.isDev()).thenReturn(false);
Controller controller = new MyController();
Route route = new Route(HttpMethod.GET, "/", controller, controller.getClass().getMethod("action"));
Route reqRoute = new Route(HttpMethod.HEAD, "/", null, null);
when(handler.router.getRouteFor(HttpMethod.HEAD, "/")).thenReturn(new Route(HttpMethod.HEAD, "/", null, null));
when(handler.router.getRouteFor(HttpMethod.GET, "/")).thenReturn(route);
RequestContext rc = new RequestContext(reqRoute, Collections.<Filter>emptyList(),
Collections.<Interceptor<?>, Object>emptyMap(), new Object[0], null);
Result result = handler.call(reqRoute, rc);
assertThat(result).isNotNull();
assertThat(result.getStatusCode()).isEqualTo(Status.OK);
assertThat(result.getRenderable().length()).isEqualTo(0);
assertThat(result.getContentType()).isEqualTo(MimeTypes.JSON);
}
@Test
public void switchToHeadWhenGetRouteDoesNotExist() throws Exception {
DefaultPageErrorHandler handler = new DefaultPageErrorHandler();
handler.configuration = mock(ApplicationConfiguration.class);
when(handler.configuration.isDev()).thenReturn(false);
handler.router = mock(Router.class);
Route reqRoute = new Route(HttpMethod.HEAD, "/", null, null);
when(handler.router.getRouteFor(HttpMethod.HEAD, "/")).thenReturn(new Route(HttpMethod.HEAD, "/", null, null));
when(handler.router.getRouteFor(HttpMethod.GET, "/")).thenReturn(new Route(HttpMethod.GET, "/", null, null));
RequestContext rc = new RequestContext(reqRoute, Collections.<Filter>emptyList(),
Collections.<Interceptor<?>, Object>emptyMap(), new Object[0], null);
Result result = handler.call(reqRoute, rc);
assertThat(result).isNotNull();
assertThat(result.getStatusCode()).isEqualTo(Status.NOT_FOUND);
assertThat(result.getRenderable().length()).isEqualTo(0);
}
@Test
public void pipelineErrorWithoutError() throws Exception {
DefaultPageErrorHandler handler = new DefaultPageErrorHandler();
handler.configuration = mock(ApplicationConfiguration.class);
when(handler.configuration.isDev()).thenReturn(true);
when(handler.configuration.getBaseDir()).thenReturn(new File("src/test/resources/wisdom/missing_on_purpose"));
handler.router = mock(Router.class);
handler.pipeline = mock(Template.class);
Request request = mock(Request.class);
when(request.accepts(MimeTypes.HTML)).thenReturn(true);
Context context = mock(Context.class);
when(context.request()).thenReturn(request);
Context.CONTEXT.set(context);
MyController controller = new MyController();
Route route = new Route(HttpMethod.GET, "/", controller, controller.getClass().getMethod("action"));
RequestContext rc = new RequestContext(route, Collections.<Filter>emptyList(),
Collections.<Interceptor<?>, Object>emptyMap(), new Object[0], null);
handler.start();
Result result = handler.call(route, rc);
assertThat(result.getStatusCode()).isEqualTo(200);
}
@Test
public void pipelineErrorWithError() throws Exception {
DefaultPageErrorHandler handler = new DefaultPageErrorHandler();
handler.configuration = mock(ApplicationConfiguration.class);
when(handler.configuration.isDev()).thenReturn(true);
when(handler.configuration.getBaseDir()).thenReturn(new File("src/test/resources/wisdom"));
handler.router = mock(Router.class);
handler.pipeline = mock(Template.class);
handler.json = mock(Json.class);
when(handler.json.parse(anyString())).thenAnswer(new Answer<JsonNode>() {
@Override
public JsonNode answer(InvocationOnMock invocation) throws Throwable {
return new ObjectMapper().readValue((String) invocation.getArguments()[0], JsonNode.class);
}
});
handler.start();
Request request = mock(Request.class);
when(request.accepts(MimeTypes.HTML)).thenReturn(true);
Context context = mock(Context.class);
when(context.request()).thenReturn(request);
Context.CONTEXT.set(context);
MyController controller = new MyController();
Route route = new Route(HttpMethod.GET, "/", controller, controller.getClass().getMethod("action"));
RequestContext rc = new RequestContext(route, Collections.<Filter>emptyList(),
Collections.<Interceptor<?>, Object>emptyMap(), new Object[0], null);
Result result = handler.call(route, rc);
assertThat(result.getStatusCode()).isEqualTo(500);
}
@Test
public void testHttpExceptionHandling() throws Exception {
DefaultPageErrorHandler handler = new DefaultPageErrorHandler();
handler.configuration = mock(ApplicationConfiguration.class);
when(handler.configuration.isDev()).thenReturn(true);
when(handler.configuration.getBaseDir()).thenReturn(new File("junk"));
handler.router = mock(Router.class);
handler.pipeline = mock(Template.class);
handler.json = mock(Json.class);
handler.mappers = new ExceptionMapper[0];
when(handler.json.parse(anyString())).thenAnswer(new Answer<JsonNode>() {
@Override
public JsonNode answer(InvocationOnMock invocation) throws Throwable {
return new ObjectMapper().readValue((String) invocation.getArguments()[0], JsonNode.class);
}
});
handler.start();
Request request = mock(Request.class);
when(request.accepts(MimeTypes.HTML)).thenReturn(true);
Context context = mock(Context.class);
when(context.request()).thenReturn(request);
Context.CONTEXT.set(context);
MyController controller = new MyController();
Route route = new Route(HttpMethod.GET, "/", controller, controller.getClass().getMethod("error"));
RequestContext rc = new RequestContext(route, Collections.<Filter>emptyList(),
Collections.<Interceptor<?>, Object>emptyMap(), new Object[0], null);
Result result = handler.call(route, rc);
assertThat(result.getStatusCode()).isEqualTo(418);
assertThat(result.getRenderable().content()).isEqualTo("bad");
}
@Test
public void testExceptionHandlingWithMappers() throws Exception {
DefaultPageErrorHandler handler = new DefaultPageErrorHandler();
handler.configuration = mock(ApplicationConfiguration.class);
when(handler.configuration.isDev()).thenReturn(true);
when(handler.configuration.getBaseDir()).thenReturn(new File("junk"));
handler.router = mock(Router.class);
handler.pipeline = mock(Template.class);
handler.json = mock(Json.class);
handler.mappers = new ExceptionMapper[]{
new ExceptionMapper<NullPointerException>() {
@Override
public Class<NullPointerException> getExceptionClass() {
return NullPointerException.class;
}
@Override
public Result toResult(NullPointerException exception) {
return new Result().status(419).render("bad");
}
}
};
when(handler.json.parse(anyString())).thenAnswer(new Answer<JsonNode>() {
@Override
public JsonNode answer(InvocationOnMock invocation) throws Throwable {
return new ObjectMapper().readValue((String) invocation.getArguments()[0], JsonNode.class);
}
});
handler.start();
Request request = mock(Request.class);
when(request.accepts(MimeTypes.HTML)).thenReturn(true);
Context context = mock(Context.class);
when(context.request()).thenReturn(request);
Context.CONTEXT.set(context);
MyController controller = new MyController();
Route route = new Route(HttpMethod.GET, "/", controller, controller.getClass().getMethod("npe"));
RequestContext rc = new RequestContext(route, Collections.<Filter>emptyList(),
Collections.<Interceptor<?>, Object>emptyMap(), new Object[0], null);
Result result = handler.call(route, rc);
assertThat(result.getStatusCode()).isEqualTo(419);
assertThat(result.getRenderable().content()).isEqualTo("bad");
route = new Route(HttpMethod.GET, "/", controller, controller.getClass().getMethod("element"));
rc = new RequestContext(route, Collections.<Filter>emptyList(),
Collections.<Interceptor<?>, Object>emptyMap(), new Object[0], null);
result = handler.call(route, rc);
assertThat(result.getStatusCode()).isEqualTo(500);
}
@After
public void cleanupContext() {
Context.CONTEXT.remove();
}
private class MyController extends DefaultController {
public Result action() {
return ok("OK").json();
}
public Result error() {
throw new HttpException(418, "bad");
}
public Result npe() {
throw new NullPointerException();
}
public Result element() {
throw new NoSuchElementException();
}
}
}