/* * Copyright (c) 2009-2011 Lockheed Martin Corporation * * 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 org.eurekastreams.commons.server; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.Serializable; import net.sf.gilead.core.PersistentBeanManager; import org.eurekastreams.commons.actions.context.PrincipalPopulator; import org.eurekastreams.commons.actions.context.service.ServiceActionContext; import org.eurekastreams.commons.actions.service.ServiceAction; import org.eurekastreams.commons.actions.service.TaskHandlerServiceAction; import org.eurekastreams.commons.client.ActionRequest; import org.eurekastreams.commons.client.ActionRequestImpl; import org.eurekastreams.commons.exceptions.AuthorizationException; import org.eurekastreams.commons.exceptions.ExecutionException; import org.eurekastreams.commons.exceptions.GeneralException; import org.eurekastreams.commons.exceptions.ValidationException; import org.eurekastreams.commons.server.service.ServiceActionController; import org.jmock.Expectations; import org.jmock.Mockery; import org.jmock.integration.junit4.JUnit4Mockery; import org.jmock.lib.legacy.ClassImposteriser; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.security.userdetails.UserDetails; /** * Unit test for ActionExecutor. */ public class ActionExecutorTest { /** * Subject under test. */ private ActionExecutor sut = null; /** * Context for building mock objects. */ private final Mockery mockContext = new JUnit4Mockery() { { setImposteriser(ClassImposteriser.INSTANCE); } }; /** * Mocked Application Spring context. */ ApplicationContext springContextMock = mockContext.mock(ApplicationContext.class); /** * Mocked UserDetails that is a valid user details object. */ private final UserDetails validUserDetailsMock = mockContext.mock(UserDetails.class); /** * Used for GWT traffic while serializing persistent objects. */ private final PersistentBeanManager persistentBeanManager = mockContext.mock(PersistentBeanManager.class); /** * Mocked PrincipalPopulator used to populate a principal object for the ServiceActionContext. */ private final PrincipalPopulator principalPopulator = mockContext.mock(PrincipalPopulator.class); /** * Mocked ServiceActionController used to execute ServiceActions. */ private final ServiceActionController serviceActionController = mockContext.mock(ServiceActionController.class); /** * The params array of Strings. */ private String[] params = null; /** * The service target. */ private static final String ACTION_KEY = "actionToExecute"; /** * Test username for the suite. */ private static final String USERNAME = "testuser"; /** Action request object. */ private ActionRequestImpl<String> defaultRequest = null; /** Action request object. */ private ActionRequestImpl<String> nullParmRequest = null; /** Fixture: action bean to execute. */ private final ServiceAction serviceAction = mockContext.mock(ServiceAction.class, "serviceAction"); /** Fixture: action bean to execute. */ private final TaskHandlerServiceAction taskHandlerAction = mockContext.mock(TaskHandlerServiceAction.class, "taskHandlerAction"); /** Fixture: generic action result. */ private final Serializable genericResult = mockContext.mock(Serializable.class, "genericResult"); /** Fixture: generic action result. */ private final Serializable genericClonedResult = mockContext.mock(Serializable.class, "genericClonedResult"); /** * . */ @SuppressWarnings("unchecked") @Before public final void setup() { params = new String[] { "echo me" }; // set up requests defaultRequest = new ActionRequestImpl<String>(ACTION_KEY, params); nullParmRequest = new ActionRequestImpl<String>(ACTION_KEY, null); mockContext.checking(new Expectations() { { allowing(springContextMock).getBean("persistentBeanManager"); will(returnValue(persistentBeanManager)); allowing(springContextMock).getBean("principalPopulator"); will(returnValue(principalPopulator)); allowing(springContextMock).getBean("serviceActionController"); will(returnValue(serviceActionController)); allowing(validUserDetailsMock).getUsername(); will(returnValue(USERNAME)); } }); } /** * Performs additional setup for a successful action execution scenario. * * @param actionBean * Object to be returned from Spring as the action bean. */ private void setupSuccess(final Object actionBean) { mockContext.checking(new Expectations() { { oneOf(springContextMock).getBean(ACTION_KEY); will(returnValue(actionBean)); oneOf(principalPopulator).getPrincipal(USERNAME, null); oneOf(persistentBeanManager).clone(with(same(genericResult))); will(returnValue(genericClonedResult)); } }); } /** * Tests the getters. */ @Test public void testGetters() { mockContext.checking(new Expectations() { { ignoring(springContextMock); } }); sut = new ActionExecutor(springContextMock, validUserDetailsMock, defaultRequest); assertNotNull("Log should not be null.", sut.getLog()); assertSame(springContextMock, sut.getSpringContext()); assertSame(validUserDetailsMock, sut.getUserDetails()); mockContext.assertIsSatisfied(); } /** * Test execution with a ServiceAction. */ @Test public final void testExecuteServiceAction() { setupSuccess(serviceAction); mockContext.checking(new Expectations() { { oneOf(serviceActionController).execute(with(any(ServiceActionContext.class)), with(same(serviceAction))); will(returnValue(genericResult)); } }); ActionRequestImpl<String> request = new ActionRequestImpl<String>(ACTION_KEY, new String("testParam")); // Test the setter on the ActionRequest class. Assert.assertEquals(request.getParam(), "testParam"); request.setParam(new String("anotherTestParam")); Assert.assertEquals(request.getParam(), "anotherTestParam"); sut = new ActionExecutor(springContextMock, validUserDetailsMock, request); // Execute the request. sut.execute(); mockContext.assertIsSatisfied(); } /** * Test execution with a TaskHandlerServiceAction. */ @Test public final void testExecuteAsyncSubmitterServiceAction() { setupSuccess(taskHandlerAction); mockContext.checking(new Expectations() { { oneOf(serviceActionController).execute(with(any(ServiceActionContext.class)), with(same(taskHandlerAction))); will(returnValue(genericResult)); } }); ActionRequestImpl<String> request = new ActionRequestImpl<String>(ACTION_KEY, new String("testParam")); // Test the setter on the ActionRequest class. Assert.assertEquals(request.getParam(), "testParam"); request.setParam(new String("anotherTestParam")); Assert.assertEquals(request.getParam(), "anotherTestParam"); sut = new ActionExecutor(springContextMock, validUserDetailsMock, request); // Execute the request. sut.execute(); mockContext.assertIsSatisfied(); } /** * Test the scenario where the bean supplied for the action is not a valid Action type. */ @SuppressWarnings("unchecked") @Test public final void testInvalidActionExecution() { mockContext.checking(new Expectations() { { oneOf(springContextMock).getBean(ACTION_KEY); will(returnValue("String")); } }); sut = new ActionExecutor(springContextMock, validUserDetailsMock, defaultRequest); // Execute the request. ActionRequest results = sut.execute(); Assert.assertTrue(results.getResponse() instanceof GeneralException); mockContext.assertIsSatisfied(); } /* ---- Test with a null parameter ---- */ /** * Test execution with a ServiceAction. */ @Test public final void testExecuteServiceActionNullParam() { setupSuccess(serviceAction); mockContext.checking(new Expectations() { { oneOf(serviceActionController).execute(with(any(ServiceActionContext.class)), with(same(serviceAction))); will(returnValue(genericResult)); } }); sut = new ActionExecutor(springContextMock, validUserDetailsMock, nullParmRequest); ActionRequest results = sut.execute(); mockContext.assertIsSatisfied(); assertSame(genericClonedResult, results.getResponse()); assertNull(results.getParam()); } /** * Test execution with a ServiceAction. */ @Test public final void testExecuteServiceActionExceptionNullParam() { mockContext.checking(new Expectations() { { oneOf(serviceActionController).execute(with(any(ServiceActionContext.class)), with(same(serviceAction))); will(throwException(new ArithmeticException())); oneOf(springContextMock).getBean(ACTION_KEY); will(returnValue(serviceAction)); oneOf(principalPopulator).getPrincipal(USERNAME, null); } }); sut = new ActionExecutor(springContextMock, validUserDetailsMock, nullParmRequest); ActionRequest results = sut.execute(); mockContext.assertIsSatisfied(); assertTrue(results.getResponse() instanceof GeneralException); assertNull(results.getParam()); } /** * Test execution with a TaskHandlerServiceAction. */ @Test public final void testExecuteTaskHandlerServiceActionNullParam() { setupSuccess(serviceAction); mockContext.checking(new Expectations() { { oneOf(serviceActionController).execute(with(any(ServiceActionContext.class)), with(same(serviceAction))); will(returnValue(genericResult)); } }); sut = new ActionExecutor(springContextMock, validUserDetailsMock, nullParmRequest); ActionRequest results = sut.execute(); mockContext.assertIsSatisfied(); assertSame(genericClonedResult, results.getResponse()); assertNull(results.getParam()); } /** * Test the scenario where the bean supplied for the action is not a valid Action type. */ @SuppressWarnings("unchecked") @Test public final void testExecuteNonActionNullParam() { mockContext.checking(new Expectations() { { oneOf(springContextMock).getBean(ACTION_KEY); will(returnValue("String")); } }); sut = new ActionExecutor(springContextMock, validUserDetailsMock, nullParmRequest); ActionRequest results = sut.execute(); mockContext.assertIsSatisfied(); assertTrue(results.getResponse() instanceof GeneralException); assertNull(results.getParam()); } /** * Test the scenario where the toString of the parameter throws an exception. */ @SuppressWarnings("unchecked") public final void testExecuteWithFaultyToString() { setupSuccess(serviceAction); final Serializable requestParm = mockContext.mock(Serializable.class, "requestParm"); mockContext.checking(new Expectations() { { allowing(requestParm).toString(); will(throwException(new ArithmeticException())); oneOf(serviceActionController).execute(with(any(ServiceActionContext.class)), with(same(serviceAction))); will(returnValue(genericResult)); } }); sut = new ActionExecutor(springContextMock, validUserDetailsMock, new ActionRequestImpl(ACTION_KEY, requestParm)); ActionRequest results = sut.execute(); mockContext.assertIsSatisfied(); assertSame(genericClonedResult, results.getResponse()); assertNull(results.getParam()); } /** * Test the scenario where the toString of the parameter throws an exception. */ @SuppressWarnings("unchecked") public final void testExecuteExceptionWithFaultyToString() { final Serializable requestParm = mockContext.mock(Serializable.class, "requestParm"); mockContext.checking(new Expectations() { { allowing(requestParm).toString(); will(throwException(new ArithmeticException())); oneOf(serviceActionController).execute(with(any(ServiceActionContext.class)), with(same(serviceAction))); will(throwException(new ArithmeticException())); oneOf(springContextMock).getBean(ACTION_KEY); will(returnValue(serviceAction)); oneOf(principalPopulator).getPrincipal(USERNAME, null); } }); sut = new ActionExecutor(springContextMock, validUserDetailsMock, new ActionRequestImpl(ACTION_KEY, requestParm)); ActionRequest results = sut.execute(); mockContext.assertIsSatisfied(); assertTrue(results.getResponse() instanceof GeneralException); assertNull(results.getParam()); } /* ---- Test action exception handling for various types of exceptions ---- */ /** * Common parts of tests that insure exceptions do not contain a nested cause. * * @param inputException * Exception to be thrown. * @return Exception returned by SUT. */ private Throwable coreForbidNestingExceptionTest(final Throwable inputException) { mockContext.checking(new Expectations() { { oneOf(springContextMock).getBean(ACTION_KEY); will(throwException(inputException)); } }); sut = new ActionExecutor(springContextMock, validUserDetailsMock, defaultRequest); ActionRequest result = sut.execute(); mockContext.assertIsSatisfied(); Serializable response = result.getResponse(); assertTrue(response instanceof Throwable); Throwable outputException = (Throwable) response; assertNull(outputException.getCause()); return outputException; } /** * Tests how exceptions are returned to client. */ @Test public void testExecutionExceptionNested() { Throwable exIn = new ExecutionException(new ArithmeticException()); Throwable exOut = coreForbidNestingExceptionTest(exIn); assertTrue(exOut instanceof ExecutionException); assertEquals(exIn.getMessage(), exOut.getMessage()); } /** * Tests how exceptions are returned to client. */ @Test public void testExecutionExceptionNonNested() { Throwable exIn = new ExecutionException(); Throwable exOut = coreForbidNestingExceptionTest(exIn); assertSame(exIn, exOut); } /** * Tests how exceptions are returned to client. */ @Test public void testGeneralExceptionNested() { Throwable exIn = new GeneralException(new ArithmeticException()); Throwable exOut = coreForbidNestingExceptionTest(exIn); assertTrue(exOut instanceof GeneralException); assertEquals(exIn.getMessage(), exOut.getMessage()); } /** * Tests how exceptions are returned to client. */ @Test public void testGeneralExceptionNonNested() { Throwable exIn = new GeneralException(); Throwable exOut = coreForbidNestingExceptionTest(exIn); assertSame(exIn, exOut); } /** * Tests how exceptions are returned to client. */ @Test public void testAuthorizationExceptionNested() { Throwable exIn = new AuthorizationException(new ArithmeticException()); Throwable exOut = coreForbidNestingExceptionTest(exIn); assertTrue(exOut instanceof AuthorizationException); assertEquals(exIn.getMessage(), exOut.getMessage()); } /** * Tests how exceptions are returned to client. */ @Test public void testAuthorizationExceptionNonNested() { Throwable exIn = new AuthorizationException(); Throwable exOut = coreForbidNestingExceptionTest(exIn); assertSame(exIn, exOut); } /** * Tests how exceptions are returned to client. */ @Test public void testValidationExceptionNonNested() { Throwable exIn = new ValidationException(); Throwable exOut = coreForbidNestingExceptionTest(exIn); assertSame(exIn, exOut); } /** * Tests how exceptions are returned to client. */ @Test public void testOtherExceptionNonNested() { Throwable exIn = new IllegalArgumentException("bad"); Throwable exOut = coreForbidNestingExceptionTest(exIn); assertTrue(exOut instanceof GeneralException); assertEquals(exIn.getMessage(), exOut.getMessage()); } /** * Tests how exceptions are returned to client. */ @Test public void testOtherExceptionNested() { Throwable exIn = new IllegalArgumentException(new IllegalStateException("really bad")); Throwable exOut = coreForbidNestingExceptionTest(exIn); assertTrue(exOut instanceof GeneralException); assertEquals(exIn.getMessage(), exOut.getMessage()); } }