From 4ac287abd7da73273b162b2dc203c3636e9cb44f Mon Sep 17 00:00:00 2001 From: Yasser Zamani Date: Sat, 25 Nov 2017 19:26:02 +0330 Subject: [PATCH] WW-4874 Adds unit tests --- .../xwork2/DefaultActionInvocationTest.java | 92 +++++++++++++- .../struts2/dispatcher/DispatcherTest.java | 30 +++++ .../dispatcher/PrepareOperationsTest.java | 42 +++++++ plugins/async/pom.xml | 18 +++ .../async/DefaultAsyncManagerTest.java | 113 ++++++++++++++++++ 5 files changed, 293 insertions(+), 2 deletions(-) create mode 100644 core/src/test/java/org/apache/struts2/dispatcher/PrepareOperationsTest.java create mode 100644 plugins/async/src/test/java/org/apache/struts2/async/DefaultAsyncManagerTest.java diff --git a/core/src/test/java/com/opensymphony/xwork2/DefaultActionInvocationTest.java b/core/src/test/java/com/opensymphony/xwork2/DefaultActionInvocationTest.java index 334839082..4226ef83a 100644 --- a/core/src/test/java/com/opensymphony/xwork2/DefaultActionInvocationTest.java +++ b/core/src/test/java/com/opensymphony/xwork2/DefaultActionInvocationTest.java @@ -22,10 +22,10 @@ import com.opensymphony.xwork2.config.entities.ActionConfig; import com.opensymphony.xwork2.config.entities.InterceptorMapping; import com.opensymphony.xwork2.config.entities.ResultConfig; import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider; +import com.opensymphony.xwork2.interceptor.PreResultListener; import com.opensymphony.xwork2.mock.MockActionProxy; import com.opensymphony.xwork2.mock.MockContainer; import com.opensymphony.xwork2.mock.MockInterceptor; -import com.opensymphony.xwork2.mock.MockLazyInterceptor; import com.opensymphony.xwork2.ognl.OgnlUtil; import com.opensymphony.xwork2.util.ValueStack; import com.opensymphony.xwork2.util.ValueStackFactory; @@ -34,7 +34,9 @@ import org.apache.struts2.dispatcher.HttpParameters; import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; /** @@ -340,6 +342,92 @@ public class DefaultActionInvocationTest extends XWorkTestCase { assertEquals("this is blah", action.getName()); } + public void testInvokeWithAsyncManager() throws Exception { + DefaultActionInvocation dai = new DefaultActionInvocation(new HashMap(), false); + dai.stack = container.getInstance(ValueStackFactory.class).createValueStack(); + + final Semaphore lock = new Semaphore(1); + lock.acquire(); + dai.setAsyncManager(new AsyncManager() { + Object asyncActionResult; + @Override + public boolean hasAsyncActionResult() { + return asyncActionResult != null; + } + + @Override + public Object getAsyncActionResult() { + return asyncActionResult; + } + + @Override + public void invokeAsyncAction(Callable asyncAction) { + try { + asyncActionResult = asyncAction.call(); + } catch (Exception e) { + asyncActionResult = e; + } + lock.release(); + } + }); + + dai.action = new Callable>() { + @Override + public Callable call() throws Exception { + return new Callable() { + @Override + public String call() throws Exception { + return "success"; + } + }; + } + }; + + MockActionProxy actionProxy = new MockActionProxy(); + actionProxy.setMethod("call"); + dai.proxy = actionProxy; + + final boolean[] preResultExecuted = new boolean[1]; + dai.addPreResultListener(new PreResultListener() { + @Override + public void beforeResult(ActionInvocation invocation, String resultCode) { + preResultExecuted[0] = true; + } + }); + + List interceptorMappings = new ArrayList<>(); + MockInterceptor mockInterceptor1 = new MockInterceptor(); + mockInterceptor1.setFoo("test1"); + mockInterceptor1.setExpectedFoo("test1"); + interceptorMappings.add(new InterceptorMapping("test1", mockInterceptor1)); + dai.interceptors = interceptorMappings.iterator(); + + dai.ognlUtil = new OgnlUtil(); + + dai.invoke(); + + assertTrue("interceptor1 should be executed", mockInterceptor1.isExecuted()); + assertFalse("preResultListener should no be executed", preResultExecuted[0]); + assertNotNull("an async action should be saved", dai.asyncAction); + assertFalse("invocation should not be executed", dai.executed); + assertNull("a null result should be passed to upper and wait for the async result", dai.resultCode); + + if(lock.tryAcquire(1500L, TimeUnit.MILLISECONDS)) { + try { + dai.invoke(); + assertTrue("preResultListener should be executed", preResultExecuted[0]); + assertNull("async action should be cleared", dai.asyncAction); + assertTrue("invocation should be executed", dai.executed); + assertEquals("success", dai.resultCode); + } finally { + lock.release(); + } + } else { + lock.release(); + fail("async result did not received on timeout!"); + } + } + @Override protected void setUp() throws Exception { super.setUp(); diff --git a/core/src/test/java/org/apache/struts2/dispatcher/DispatcherTest.java b/core/src/test/java/org/apache/struts2/dispatcher/DispatcherTest.java index 7e25fb11f..6ff918653 100644 --- a/core/src/test/java/org/apache/struts2/dispatcher/DispatcherTest.java +++ b/core/src/test/java/org/apache/struts2/dispatcher/DispatcherTest.java @@ -20,7 +20,9 @@ package org.apache.struts2.dispatcher; import com.mockobjects.dynamic.C; import com.mockobjects.dynamic.Mock; +import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ObjectFactory; +import com.opensymphony.xwork2.StubValueStack; import com.opensymphony.xwork2.XWorkConstants; import com.opensymphony.xwork2.config.Configuration; import com.opensymphony.xwork2.config.ConfigurationManager; @@ -30,8 +32,12 @@ import com.opensymphony.xwork2.config.entities.PackageConfig; import com.opensymphony.xwork2.inject.Container; import com.opensymphony.xwork2.interceptor.Interceptor; import com.opensymphony.xwork2.LocalizedTextProvider; +import com.opensymphony.xwork2.mock.MockActionInvocation; +import com.opensymphony.xwork2.mock.MockActionProxy; +import org.apache.struts2.ServletActionContext; import org.apache.struts2.StrutsConstants; import org.apache.struts2.StrutsInternalTestCase; +import org.apache.struts2.dispatcher.mapper.ActionMapping; import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper; import org.apache.struts2.util.ObjectFactoryDestroyable; import org.springframework.mock.web.MockHttpServletRequest; @@ -321,6 +327,30 @@ public class DispatcherTest extends StrutsInternalTestCase { assertTrue(du.isMultipartRequest(req)); } + public void testServiceActionResumePreviousProxy() throws Exception { + Dispatcher du = initDispatcher(Collections.emptyMap()); + + MockActionInvocation mai = new MockActionInvocation(); + ActionContext.getContext().setActionInvocation(mai); + + MockActionProxy actionProxy = new MockActionProxy(); + actionProxy.setInvocation(mai); + mai.setProxy(actionProxy); + + mai.setStack(new StubValueStack()); + + HttpServletRequest req = new MockHttpServletRequest(); + req.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, mai.getStack()); + + assertFalse(actionProxy.isExecutedCalled()); + + du.setDevMode("false"); + du.setHandleException("false"); + du.serviceAction(req, null, new ActionMapping()); + + assertTrue("should execute previous proxy", actionProxy.isExecutedCalled()); + } + class InternalConfigurationManager extends ConfigurationManager { public boolean destroyConfiguration = false; diff --git a/core/src/test/java/org/apache/struts2/dispatcher/PrepareOperationsTest.java b/core/src/test/java/org/apache/struts2/dispatcher/PrepareOperationsTest.java new file mode 100644 index 000000000..02b705b11 --- /dev/null +++ b/core/src/test/java/org/apache/struts2/dispatcher/PrepareOperationsTest.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.struts2.dispatcher; + +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.StubValueStack; +import org.apache.struts2.ServletActionContext; +import org.apache.struts2.StrutsInternalTestCase; +import org.springframework.mock.web.MockHttpServletRequest; + +import javax.servlet.http.HttpServletRequest; + +public class PrepareOperationsTest extends StrutsInternalTestCase { + public void testCreateActionContextWhenRequestHasOne() { + HttpServletRequest req = new MockHttpServletRequest(); + StubValueStack stack = new StubValueStack(); + req.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack); + + PrepareOperations prepare = new PrepareOperations(null); + + ActionContext.setContext(null); + ActionContext actionContext = prepare.createActionContext(req, null); + + assertEquals(stack.getContext(), actionContext.getContextMap()); + } +} diff --git a/plugins/async/pom.xml b/plugins/async/pom.xml index 6ed07cff8..b5e5ae02b 100644 --- a/plugins/async/pom.xml +++ b/plugins/async/pom.xml @@ -42,5 +42,23 @@ 3.0.1 provided + + + mockobjects + mockobjects-core + test + + + + org.springframework + spring-test + test + + + + org.springframework + spring-web + test + diff --git a/plugins/async/src/test/java/org/apache/struts2/async/DefaultAsyncManagerTest.java b/plugins/async/src/test/java/org/apache/struts2/async/DefaultAsyncManagerTest.java new file mode 100644 index 000000000..f4bc21bef --- /dev/null +++ b/plugins/async/src/test/java/org/apache/struts2/async/DefaultAsyncManagerTest.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.struts2.async; + +import com.opensymphony.xwork2.XWorkTestCase; +import org.apache.struts2.ServletActionContext; +import org.springframework.mock.web.MockAsyncContext; +import org.springframework.mock.web.MockHttpServletRequest; + +import java.util.concurrent.Callable; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +public class DefaultAsyncManagerTest extends XWorkTestCase { + public void testInvokeAsyncAction() throws Exception { + final MockHttpServletRequest request = new MockHttpServletRequest(); + request.setAsyncSupported(true); + + ServletActionContext.setRequest(request); + + final Semaphore lock = new Semaphore(1); + lock.acquire(); + + AsyncAction asyncAction = new AsyncAction(new Callable() { + @Override + public Object call() throws Exception { + final MockAsyncContext mockAsyncContext = (MockAsyncContext) request.getAsyncContext(); + mockAsyncContext.addDispatchHandler(new Runnable() { + @Override + public void run() { + mockAsyncContext.complete(); + lock.release(); + } + }); + + return "success"; + } + }); + + DefaultAsyncManager asyncManager = new DefaultAsyncManager(); + asyncManager.invokeAsyncAction(asyncAction); + asyncManager.invokeAsyncAction(asyncAction); // duplicate invoke should not raise any problem + + if (lock.tryAcquire(1500L, TimeUnit.MILLISECONDS)) { + try { + assertTrue("an async result is expected", asyncManager.hasAsyncActionResult()); + assertEquals("success", asyncManager.getAsyncActionResult()); + } finally { + lock.release(); + } + } else { + lock.release(); + fail("async result did not received on timeout!"); + } + } + + public void testInvokeAsyncActionException() throws Exception { + final MockHttpServletRequest request = new MockHttpServletRequest(); + request.setAsyncSupported(true); + + ServletActionContext.setRequest(request); + + final Semaphore lock = new Semaphore(1); + lock.acquire(); + + final Exception expected = new Exception(); + AsyncAction asyncAction = new AsyncAction(new Callable() { + @Override + public Object call() throws Exception { + final MockAsyncContext mockAsyncContext = (MockAsyncContext) request.getAsyncContext(); + mockAsyncContext.addDispatchHandler(new Runnable() { + @Override + public void run() { + mockAsyncContext.complete(); + lock.release(); + } + }); + + throw expected; + } + }); + + DefaultAsyncManager asyncManager = new DefaultAsyncManager(); + asyncManager.invokeAsyncAction(asyncAction); + + if (lock.tryAcquire(1500L, TimeUnit.MILLISECONDS)) { + try { + assertTrue("an async result is expected", asyncManager.hasAsyncActionResult()); + assertEquals(expected, asyncManager.getAsyncActionResult()); + } finally { + lock.release(); + } + } else { + fail("async result did not received on timeout!"); + } + } +}