/******************************************************************************* * Copyright (c) 2012, Directors of the Tyndale STEP Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * Neither the name of the Tyndale House, Cambridge (www.TyndaleHouse.com) * nor the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ package com.tyndalehouse.step.rest.framework; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Locale; import javax.inject.Provider; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.tyndalehouse.step.core.service.AppManagerService; import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.map.ObjectMapper; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import com.google.inject.Injector; import com.tyndalehouse.step.core.exceptions.StepInternalException; import com.tyndalehouse.step.core.models.ClientSession; import com.tyndalehouse.step.core.service.BibleInformationService; import com.tyndalehouse.step.guice.providers.ClientSessionProvider; import com.tyndalehouse.step.rest.controllers.BibleController; /** * tests the front controller parsing process * * @author chrisburrell */ @SuppressWarnings("PMD.TooManyMethods") @RunWith(MockitoJUnitRunner.class) public class FrontControllerTest { private FrontController fcUnderTest; @Mock private Injector guiceInjector; @Mock private ClientErrorResolver errorResolver; @Mock private StepRequest stepRequest; @Mock private ClientSessionProvider clientSessionProvider; @Mock private Provider<ObjectMapper> objectMapper; /** * Simply setting up the FrontController under test */ @Before public void setUp() throws IOException { final ClientSession clientSession = mock(ClientSession.class); when(clientSession.getLocale()).thenReturn(Locale.ENGLISH); when(this.clientSessionProvider.get()).thenReturn(clientSession); final ObjectMapper mockMapper = mock(ObjectMapper.class); when(mockMapper.writeValueAsString(any(Object.class))).thenReturn("Test"); when(this.objectMapper.get()).thenReturn(mockMapper); this.fcUnderTest = new FrontController(this.guiceInjector, mock(AppManagerService.class), this.errorResolver, this.clientSessionProvider, objectMapper); } /** * Tests normal operation of a GET method * * @throws IOException uncaught exception */ @Test public void testDoGet() throws Exception { final HttpServletRequest req = mock(HttpServletRequest.class); final HttpServletResponse response = mock(HttpServletResponse.class); final String sampleRequest = "step-web/rest/bible/get/1K2/2K2/"; when(req.getRequestURI()).thenReturn(sampleRequest); when(req.getServletPath()).thenReturn("step-web/"); when(req.getContextPath()).thenReturn("rest/"); final FrontController fc = spy(this.fcUnderTest); final ServletOutputStream mockOutputStream = mock(ServletOutputStream.class); doReturn(mockOutputStream).when(response).getOutputStream(); final byte[] sampleResponse = new byte[]{1, 2, 3}; doReturn(sampleResponse).when(fc).invokeMethodWithStepRequest(any(StepRequest.class)); // do the test assertEquals(sampleResponse, fc.invokeMethod(req)); } /** * tests what happens when doGet catches an exception */ @Test public void testDoGetHasException() { final HttpServletRequest request = mock(HttpServletRequest.class); final HttpServletResponse response = mock(HttpServletResponse.class); final StepInternalException testException = new StepInternalException("A test exception"); final FrontController fc = spy(this.fcUnderTest); final StepRequest parsedRequest = new StepRequest("blah", "SomeController", "someMethod", new String[]{"arg1", "arg2"}); // TODO remove this/ doNothing().when(fc).handleError(response, testException, mock(HttpServletRequest.class)); // do the test fc.doGet(request, response); } /** * tests that the headers are setup correctly */ @Test public void testHeadersSetupCorrectly() { final HttpServletResponse response = mock(HttpServletResponse.class); final int sampleRequestLength = 10; this.fcUnderTest.setupHeaders(response, sampleRequestLength); verify(response).addDateHeader(eq("Date"), anyLong()); verify(response).setCharacterEncoding("UTF-8"); verify(response).setContentType("application/json"); verify(response).setContentLength(sampleRequestLength); } /** * tests that resolving method works * * @throws IllegalAccessException uncaught exception * @throws InvocationTargetException uncaught exception */ @Test public void testGetControllerMethod() throws IllegalAccessException, InvocationTargetException { final BibleInformationService bibleInfo = mock(BibleInformationService.class); final BibleController controllerInstance = new BibleController(bibleInfo, this.clientSessionProvider, null); // when final Method controllerMethod = this.fcUnderTest.getControllerMethod("getAllFeatures", controllerInstance, null, null); // then controllerMethod.invoke(controllerInstance); verify(bibleInfo).getAllFeatures(); } /** * tests the get controller method */ @Test public void testGetController() { final String controllerName = "Bible"; final BibleController mockController = mock(BibleController.class); when(this.guiceInjector.getInstance(BibleController.class)).thenReturn(mockController); // when final Object controller = this.fcUnderTest.getController(controllerName, false); // then assertEquals(controller.getClass(), mockController.getClass()); } /** * tests various combinations for getClasses */ @Test public void testGetClasses() { assertEquals(0, this.fcUnderTest.getClasses(null).length); assertEquals(0, this.fcUnderTest.getClasses(new Object[0]).length); assertArrayEquals(new Class<?>[]{String.class, Integer.class}, this.fcUnderTest.getClasses(new Object[]{"hello", Integer.valueOf(1)})); } /** * If an error was thrown, we should map it and output * * @throws IOException uncaught exception */ @Test public void testDoErrorHandlesCorrectly() throws IOException { final HttpServletResponse response = mock(HttpServletResponse.class); // final StepRequest stepRequest = new StepRequest("blah", "controller", "method", null); final ServletOutputStream outputStream = mock(ServletOutputStream.class); final Throwable exception = new Exception(); when(response.getOutputStream()).thenReturn(outputStream); when(this.stepRequest.getCacheKey()).thenReturn(new ControllerCacheKey("method", "results")); // do test this.fcUnderTest.handleError(response, exception, mock(HttpServletRequest.class)); // check verify(outputStream).write(any(byte[].class)); } /** * We check that invoke method calls the correct controller and method with the right arguments */ @Test public void testInvokeMethod() throws Exception { final StepRequest sr = new StepRequest("blah", "bible", "getAllFeatures", new String[]{}); final BibleController testController = mock(BibleController.class); final FrontController fc = spy(this.fcUnderTest); doReturn(testController).when(fc).getController("bible", false); // do test fc.invokeMethodWithStepRequest(sr); // verify verify(testController).getAllFeatures(); } }