/******************************************************************************* * Copyright (c) 2012-2016 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.everrest.core.impl; import org.everrest.core.ApplicationContext; import org.everrest.core.RequestFilter; import org.everrest.core.ResponseFilter; import org.everrest.core.UnhandledException; import org.everrest.core.tools.ErrorPages; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.mockito.ArgumentCaptor; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MultivaluedHashMap; import javax.ws.rs.core.Response; import javax.ws.rs.ext.ExceptionMapper; import static com.google.common.collect.Lists.newArrayList; import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; import static javax.ws.rs.core.Response.serverError; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public class RequestHandlerImplTest { @Rule public ExpectedException thrown = ExpectedException.none(); private final String requestPath = "/a/b/c"; private ContainerRequest request; private ContainerResponse response; private RequestDispatcher requestDispatcher; private ProviderBinder providers; private EnvironmentContext environmentContext; private RequestHandlerImpl requestHandler; @Before public void setUp() throws Exception { environmentContext = mock(EnvironmentContext.class); EnvironmentContext.setCurrent(environmentContext); ApplicationContext applicationContext = mock(ApplicationContext.class); when(applicationContext.getPath()).thenReturn(requestPath); when(applicationContext.getQueryParameters()).thenReturn(new MultivaluedHashMap<>()); ApplicationContext.setCurrent(applicationContext); request = mock(ContainerRequest.class); response = mock(ContainerResponse.class); when(response.getHttpHeaders()).thenReturn(new MultivaluedHashMap<>()); requestDispatcher = mock(RequestDispatcher.class); providers = mock(ProviderBinder.class); requestHandler = new RequestHandlerImpl(requestDispatcher, providers); } @Test public void executesRequestWithRequestDispatcher() throws Exception { requestHandler.handleRequest(request, response); verify(requestDispatcher).dispatch(request, response); } @Test public void appliesRequestFilters() throws Exception { RequestFilter requestFilter = mock(RequestFilter.class); when(providers.getRequestFilters(requestPath)).thenReturn(newArrayList(requestFilter)); requestHandler.handleRequest(request, response); verify(requestFilter).doFilter(request); } @Test public void appliesResponseFilters() throws Exception { ResponseFilter responseFilter = mock(ResponseFilter.class); when(providers.getResponseFilters(requestPath)).thenReturn(newArrayList(responseFilter)); requestHandler.handleRequest(request, response); verify(responseFilter).doFilter(response); } @Test public void wrapsUnexpectedExceptionWithUnhandledException() throws Exception { RuntimeException exception = new RuntimeException(); doThrow(exception).when(requestDispatcher).dispatch(request, response); thrown.expect(UnhandledException.class); thrown.expectCause(exceptionSameInstanceMatcher(exception)); requestHandler.handleRequest(request, response); } @Test public void sendsResponseFromThrownWebApplicationExceptionWhenResponseHasEntity() throws Exception { WebApplicationException exception = new WebApplicationException(serverError().entity("Some Error").build()); doThrow(exception).when(requestDispatcher).dispatch(request, response); requestHandler.handleRequest(request, response); ArgumentCaptor<Response> argumentCaptor = ArgumentCaptor.forClass(Response.class); verify(response).setResponse(argumentCaptor.capture()); assertEquals(INTERNAL_SERVER_ERROR, argumentCaptor.getValue().getStatusInfo()); assertEquals("Some Error", argumentCaptor.getValue().getEntity()); } @Test public void throwsUnhandledExceptionWithCauseOfWebApplicationExceptionWhenJspErrorPageIsAvailableForErrorStatus() throws Exception { ErrorPages errorPages = mock(ErrorPages.class); when(errorPages.hasErrorPage(403)).thenReturn(true); when(environmentContext.get(ErrorPages.class)).thenReturn(errorPages); WebApplicationException webApplicationException = new WebApplicationException(403); doThrow(webApplicationException).when(requestDispatcher).dispatch(request, response); thrown.expect(UnhandledException.class); thrown.expect(unhandledExceptionWIthStatusMatcher(403)); requestHandler.handleRequest(request, response); } @Test public void throwsUnhandledExceptionWithCauseOfWebApplicationExceptionWhenJspErrorPageForCauseIsAvailable() throws Exception { ErrorPages errorPages = mock(ErrorPages.class); Exception exception = new Exception(); when(errorPages.hasErrorPage(exception)).thenReturn(true); when(environmentContext.get(ErrorPages.class)).thenReturn(errorPages); WebApplicationException webApplicationException = new WebApplicationException(exception); doThrow(webApplicationException).when(requestDispatcher).dispatch(request, response); thrown.expect(UnhandledException.class); thrown.expectCause(exceptionSameInstanceMatcher(exception)); requestHandler.handleRequest(request, response); } @Test public void throwsUnhandledExceptionWithWebApplicationExceptionWhenJspErrorPageForWebApplicationExceptionIsAvailable() throws Exception { ErrorPages errorPages = mock(ErrorPages.class); WebApplicationException webApplicationException = new WebApplicationException(); when(errorPages.hasErrorPage(webApplicationException)).thenReturn(true); when(environmentContext.get(ErrorPages.class)).thenReturn(errorPages); doThrow(webApplicationException).when(requestDispatcher).dispatch(request, response); thrown.expect(UnhandledException.class); thrown.expectCause(exceptionSameInstanceMatcher(webApplicationException)); requestHandler.handleRequest(request, response); } @Test public void usesExceptionMapperToConvertWebApplicationExceptionToResponseWhenResponseFromWebApplicationExceptionDoesNotHaveEntity() throws Exception { WebApplicationException webApplicationException = new WebApplicationException(serverError().build()); doThrow(webApplicationException).when(requestDispatcher).dispatch(request, response); ExceptionMapper<WebApplicationException> exceptionMapper = mock(ExceptionMapper.class); when(exceptionMapper.toResponse(webApplicationException)).thenReturn(serverError().entity("response from exception mapper").build()); when(providers.getExceptionMapper(WebApplicationException.class)).thenReturn(exceptionMapper); requestHandler.handleRequest(request, response); ArgumentCaptor<Response> argumentCaptor = ArgumentCaptor.forClass(Response.class); verify(response).setResponse(argumentCaptor.capture()); assertEquals(INTERNAL_SERVER_ERROR, argumentCaptor.getValue().getStatusInfo()); assertEquals("response from exception mapper", argumentCaptor.getValue().getEntity()); } @Test public void usesMessageFromCauseOfWebApplicationExceptionForResponseEntityWhenResponseFromWebApplicationExceptionDoesNotHaveEntity() throws Exception { Exception exception = new Exception("Error message"); WebApplicationException webApplicationException = new WebApplicationException(exception); doThrow(webApplicationException).when(requestDispatcher).dispatch(request, response); requestHandler.handleRequest(request, response); ArgumentCaptor<Response> argumentCaptor = ArgumentCaptor.forClass(Response.class); verify(response).setResponse(argumentCaptor.capture()); assertEquals(INTERNAL_SERVER_ERROR, argumentCaptor.getValue().getStatusInfo()); assertEquals("Error message", argumentCaptor.getValue().getEntity()); } @Test public void usesMessageFromWebApplicationExceptionForResponseEntityWhenResponseFromWebApplicationExceptionDoesNotHaveEntity() throws Exception { WebApplicationException webApplicationException = new WebApplicationException("Error message"); doThrow(webApplicationException).when(requestDispatcher).dispatch(request, response); requestHandler.handleRequest(request, response); ArgumentCaptor<Response> argumentCaptor = ArgumentCaptor.forClass(Response.class); verify(response).setResponse(argumentCaptor.capture()); assertEquals(INTERNAL_SERVER_ERROR, argumentCaptor.getValue().getStatusInfo()); assertEquals("Error message", argumentCaptor.getValue().getEntity()); } @Test public void usesToStringOfCauseOfWebApplicationExceptionForResponseEntityWhenResponseFromWebApplicationExceptionDoesNotHaveEntityAndCauseDoesNotHaveMessage() throws Exception { Exception exception = new Exception(); WebApplicationException webApplicationException = new WebApplicationException(exception); doThrow(webApplicationException).when(requestDispatcher).dispatch(request, response); requestHandler.handleRequest(request, response); ArgumentCaptor<Response> argumentCaptor = ArgumentCaptor.forClass(Response.class); verify(response).setResponse(argumentCaptor.capture()); assertEquals(INTERNAL_SERVER_ERROR, argumentCaptor.getValue().getStatusInfo()); assertEquals(exception.toString(), argumentCaptor.getValue().getEntity()); } @Test public void throwsUnhandledExceptionWithCauseOfInternalExceptionWhenJspErrorPageForCauseIsAvailable() throws Exception { ErrorPages errorPages = mock(ErrorPages.class); Exception exception = new Exception(); when(errorPages.hasErrorPage(exception)).thenReturn(true); when(environmentContext.get(ErrorPages.class)).thenReturn(errorPages); InternalException internalException = new InternalException(exception); doThrow(internalException).when(requestDispatcher).dispatch(request, response); thrown.expect(UnhandledException.class); thrown.expectCause(exceptionSameInstanceMatcher(exception)); requestHandler.handleRequest(request, response); } @Test public void throwsUnhandledExceptionWithInternalExceptionWhenJspErrorPageForInternalExceptionIsAvailable() throws Exception { ErrorPages errorPages = mock(ErrorPages.class); InternalException internalException = new InternalException(new Exception()); when(errorPages.hasErrorPage(internalException)).thenReturn(true); when(environmentContext.get(ErrorPages.class)).thenReturn(errorPages); doThrow(internalException).when(requestDispatcher).dispatch(request, response); thrown.expect(UnhandledException.class); thrown.expectCause(exceptionSameInstanceMatcher(internalException)); requestHandler.handleRequest(request, response); } @Test public void usesExceptionMapperToConvertCauseOfInternalExceptionToResponse() throws Exception { Exception exception = new Exception(); InternalException internalException = new InternalException(exception); doThrow(internalException).when(requestDispatcher).dispatch(request, response); ExceptionMapper<Exception> exceptionMapper = mock(ExceptionMapper.class); when(exceptionMapper.toResponse(exception)).thenReturn(serverError().entity("response from exception mapper").build()); when(providers.getExceptionMapper(Exception.class)).thenReturn(exceptionMapper); requestHandler.handleRequest(request, response); ArgumentCaptor<Response> argumentCaptor = ArgumentCaptor.forClass(Response.class); verify(response).setResponse(argumentCaptor.capture()); assertEquals(INTERNAL_SERVER_ERROR, argumentCaptor.getValue().getStatusInfo()); assertEquals("response from exception mapper", argumentCaptor.getValue().getEntity()); } @Test public void throwsUnhandledExceptionWithCauseOfInternalExceptionWhenExceptionMapperForCauseIsNotAvailable() throws Exception { Exception exception = new Exception(); InternalException internalException = new InternalException(exception); doThrow(internalException).when(requestDispatcher).dispatch(request, response); when(providers.getExceptionMapper(Exception.class)).thenReturn(null); thrown.expect(UnhandledException.class); thrown.expectCause(exceptionSameInstanceMatcher(exception)); requestHandler.handleRequest(request, response); } private BaseMatcher<Throwable> exceptionSameInstanceMatcher(Exception expectedException) { return new BaseMatcher<Throwable>() { @Override public boolean matches(Object item) { return item == expectedException; } @Override public void describeTo(Description description) { description.appendText(String.format("Expected exception: %s", expectedException)); } }; } private BaseMatcher<Throwable> unhandledExceptionWIthStatusMatcher(int status) { return new BaseMatcher<Throwable>() { @Override public boolean matches(Object item) { return ((UnhandledException)item).getResponseStatus() == status; } @Override public void describeTo(Description description) { description.appendText(String.format("Expected UnhandledException with status: %s", status)); } }; } }