package org.springframework.webflow.mvc.servlet; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import junit.framework.TestCase; import org.easymock.EasyMock; import org.springframework.js.ajax.SpringJavascriptAjaxHandler; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockServletContext; import org.springframework.web.context.support.StaticWebApplicationContext; import org.springframework.web.servlet.ModelAndView; import org.springframework.webflow.context.servlet.ServletExternalContext; import org.springframework.webflow.core.FlowException; import org.springframework.webflow.core.collection.LocalAttributeMap; import org.springframework.webflow.core.collection.MutableAttributeMap; import org.springframework.webflow.execution.FlowExecutionOutcome; import org.springframework.webflow.execution.repository.NoSuchFlowExecutionException; import org.springframework.webflow.executor.FlowExecutionResult; import org.springframework.webflow.executor.FlowExecutor; import org.springframework.webflow.test.MockFlowExecutionKey; public class FlowControllerTests extends TestCase { private FlowController controller; private FlowExecutor executor; private MockHttpServletRequest request; private MockHttpServletResponse response; private ServletExternalContext context; protected void setUp() throws Exception { executor = EasyMock.createMock(FlowExecutor.class); controller = new FlowController(); FlowHandlerAdapter handlerAdapter = new FlowHandlerAdapter() { protected ServletExternalContext createServletExternalContext(HttpServletRequest request, HttpServletResponse response) { return context; } }; handlerAdapter.setFlowExecutor(executor); StaticWebApplicationContext applicationContext = new StaticWebApplicationContext(); MockServletContext servletContext = new MockServletContext(); applicationContext.setServletContext(servletContext); handlerAdapter.setApplicationContext(applicationContext); handlerAdapter.afterPropertiesSet(); controller.setFlowHandlerAdapter(handlerAdapter); controller.setApplicationContext(new StaticWebApplicationContext()); controller.afterPropertiesSet(); request = new MockHttpServletRequest(); response = new MockHttpServletResponse(); context = new ServletExternalContext(servletContext, request, response, controller.getFlowUrlHandler()); } public void testLaunchFlowRequest() throws Exception { request.setContextPath("/springtravel"); request.setServletPath("/app"); request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); executor.launchExecution("foo", null, context); FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345"); EasyMock.expectLastCall().andReturn(result); EasyMock.replay(new Object[] { executor }); ModelAndView mv = controller.handleRequest(request, response); assertNull(mv); EasyMock.verify(new Object[] { executor }); } public void testLaunchFlowRequestEndsAfterProcessing() throws Exception { request.setContextPath("/springtravel"); request.setServletPath("/app"); request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); executor.launchExecution("foo", null, context); LocalAttributeMap<Object> output = new LocalAttributeMap<Object>(); output.put("bar", "baz"); FlowExecutionOutcome outcome = new FlowExecutionOutcome("finish", output); FlowExecutionResult result = FlowExecutionResult.createEndedResult("foo", outcome); EasyMock.expectLastCall().andReturn(result); EasyMock.replay(new Object[] { executor }); ModelAndView mv = controller.handleRequest(request, response); assertNull(mv); assertEquals("/springtravel/app/foo?bar=baz", response.getRedirectedUrl()); EasyMock.verify(new Object[] { executor }); } public void testResumeFlowRequest() throws Exception { request.setContextPath("/springtravel"); request.setServletPath("/app"); request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("POST"); request.addParameter("execution", "12345"); Map<String, String> parameters = new HashMap<String, String>(); request.setParameters(parameters); executor.resumeExecution("12345", context); FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "123456"); EasyMock.expectLastCall().andReturn(result); EasyMock.replay(new Object[] { executor }); ModelAndView mv = controller.handleRequest(request, response); assertNull(mv); EasyMock.verify(new Object[] { executor }); } public void testResumeFlowRequestEndsAfterProcessing() throws Exception { request.setContextPath("/springtravel"); request.setServletPath("/app"); request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("POST"); request.addParameter("execution", "12345"); Map<String, String> parameters = new HashMap<String, String>(); request.setParameters(parameters); executor.resumeExecution("12345", context); LocalAttributeMap<Object> output = new LocalAttributeMap<Object>(); output.put("bar", "baz"); FlowExecutionOutcome outcome = new FlowExecutionOutcome("finish", output); FlowExecutionResult result = FlowExecutionResult.createEndedResult("foo", outcome); EasyMock.expectLastCall().andReturn(result); EasyMock.replay(new Object[] { executor }); ModelAndView mv = controller.handleRequest(request, response); assertNull(mv); assertEquals("/springtravel/app/foo?bar=baz", response.getRedirectedUrl()); EasyMock.verify(new Object[] { executor }); } public void testLaunchFlowWithExecutionRedirect() throws Exception { request.setContextPath("/springtravel"); request.setServletPath("/app"); request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); context.requestFlowExecutionRedirect(); executor.launchExecution("foo", null, context); FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345"); EasyMock.expectLastCall().andReturn(result); EasyMock.replay(new Object[] { executor }); ModelAndView mv = controller.handleRequest(request, response); assertNull(mv); assertEquals("/springtravel/app/foo?execution=12345", response.getRedirectedUrl()); EasyMock.verify(new Object[] { executor }); } public void testLaunchFlowWithExecutionRedirectAjaxHeaderOpenInPopup() throws Exception { request.setContextPath("/springtravel"); request.setServletPath("/app"); request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); request.addHeader("Accept", "text/html;type=ajax"); context.setAjaxRequest(true); context.requestFlowExecutionRedirect(); context.requestRedirectInPopup(); executor.launchExecution("foo", null, context); FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345"); EasyMock.expectLastCall().andReturn(result); EasyMock.replay(new Object[] { executor }); ModelAndView mv = controller.handleRequest(request, response); assertNull(mv); assertEquals(null, response.getRedirectedUrl()); assertEquals("true", response.getHeader(SpringJavascriptAjaxHandler.POPUP_VIEW_HEADER)); assertEquals("/springtravel/app/foo?execution=12345", response.getHeader(SpringJavascriptAjaxHandler.REDIRECT_URL_HEADER)); EasyMock.verify(new Object[] { executor }); } public void testLaunchFlowWithExecutionRedirectAjaxParameter() throws Exception { request.setContextPath("/springtravel"); request.setServletPath("/app"); request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); request.addParameter("ajaxSource", "this"); context.setAjaxRequest(true); context.requestFlowExecutionRedirect(); LocalAttributeMap<Object> inputMap = new LocalAttributeMap<Object>(); inputMap.put("ajaxSource", "this"); executor.launchExecution("foo", inputMap, context); FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345"); EasyMock.expectLastCall().andReturn(result); EasyMock.replay(new Object[] { executor }); ModelAndView mv = controller.handleRequest(request, response); assertNull(mv); assertEquals(null, response.getRedirectedUrl()); assertEquals(null, response.getHeader(SpringJavascriptAjaxHandler.POPUP_VIEW_HEADER)); assertEquals("/springtravel/app/foo?execution=12345", response.getHeader(SpringJavascriptAjaxHandler.REDIRECT_URL_HEADER)); EasyMock.verify(new Object[] { executor }); } public void testLaunchFlowWithDefinitionRedirect() throws Exception { request.setContextPath("/springtravel"); request.setServletPath("/app"); request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); LocalAttributeMap<Object> input = new LocalAttributeMap<Object>(); input.put("baz", "boop"); context.requestFlowDefinitionRedirect("bar", input); executor.launchExecution("foo", null, context); LocalAttributeMap<Object> output = new LocalAttributeMap<Object>(); output.put("bar", "baz"); FlowExecutionOutcome outcome = new FlowExecutionOutcome("finish", output); FlowExecutionResult result = FlowExecutionResult.createEndedResult("foo", outcome); EasyMock.expectLastCall().andReturn(result); EasyMock.replay(new Object[] { executor }); ModelAndView mv = controller.handleRequest(request, response); assertNull(mv); EasyMock.verify(new Object[] { executor }); assertEquals("/springtravel/app/bar?baz=boop", response.getRedirectedUrl()); EasyMock.verify(new Object[] { executor }); } public void testLaunchFlowWithExternalRedirect() throws Exception { request.setContextPath("/springtravel"); request.setServletPath("/app"); request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); context.requestExternalRedirect("http://www.paypal.com"); executor.launchExecution("foo", null, context); FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345"); EasyMock.expectLastCall().andReturn(result); EasyMock.replay(new Object[] { executor }); ModelAndView mv = controller.handleRequest(request, response); assertNull(mv); EasyMock.verify(new Object[] { executor }); assertEquals("http://www.paypal.com", response.getRedirectedUrl()); EasyMock.verify(new Object[] { executor }); } public void testDefaultHandleFlowException() throws Exception { request.setContextPath("/springtravel"); request.setServletPath("/app"); request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); executor.launchExecution("foo", null, context); FlowException flowException = new FlowException("Error") { }; EasyMock.expectLastCall().andThrow(flowException); EasyMock.replay(new Object[] { executor }); try { controller.handleRequest(request, response); fail("Should have thrown exception"); } catch (FlowException e) { assertEquals(flowException, e); } EasyMock.verify(new Object[] { executor }); } public void testDefaultHandleNoSuchFlowExecutionException() throws Exception { request.setContextPath("/springtravel"); request.setServletPath("/app"); request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); request.addParameter("execution", "12345"); executor.resumeExecution("12345", context); FlowException flowException = new NoSuchFlowExecutionException(new MockFlowExecutionKey("12345"), null); EasyMock.expectLastCall().andThrow(flowException); EasyMock.replay(new Object[] { executor }); ModelAndView mv = controller.handleRequest(request, response); assertNull(mv); assertEquals("/springtravel/app/foo", response.getRedirectedUrl()); EasyMock.verify(new Object[] { executor }); } public void testLaunchFlowWithCustomFlowHandler() throws Exception { final LocalAttributeMap<Object> input = new LocalAttributeMap<Object>(); input.put("bar", "boop"); controller.registerFlowHandler(new FlowHandler() { public String getFlowId() { return "foo"; } public MutableAttributeMap<Object> createExecutionInputMap(HttpServletRequest request) { return input; } public String handleExecutionOutcome(FlowExecutionOutcome outcome, HttpServletRequest request, HttpServletResponse response) { return null; } public String handleException(FlowException e, HttpServletRequest request, HttpServletResponse response) { return null; } }); request.setContextPath("/springtravel"); request.setServletPath("/app"); request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); executor.launchExecution("foo", input, context); FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345"); EasyMock.expectLastCall().andReturn(result); EasyMock.replay(new Object[] { executor }); ModelAndView mv = controller.handleRequest(request, response); assertNull(mv); EasyMock.verify(new Object[] { executor }); } public void testHandleFlowOutcomeCustomFlowHandler() throws Exception { final LocalAttributeMap<Object> input = new LocalAttributeMap<Object>(); input.put("bar", "boop"); controller.registerFlowHandler(new FlowHandler() { public String getFlowId() { return "foo"; } public MutableAttributeMap<Object> createExecutionInputMap(HttpServletRequest request) { return input; } public String handleExecutionOutcome(FlowExecutionOutcome outcome, HttpServletRequest request, HttpServletResponse response) { assertEquals("finish", outcome.getId()); assertEquals("baz", outcome.getOutput().get("bar")); assertEquals(FlowControllerTests.this.request, request); assertEquals(FlowControllerTests.this.response, response); return null; } public String handleException(FlowException e, HttpServletRequest request, HttpServletResponse response) { return null; } }); request.setContextPath("/springtravel"); request.setServletPath("/app"); request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); executor.launchExecution("foo", input, context); LocalAttributeMap<Object> output = new LocalAttributeMap<Object>(); output.put("bar", "baz"); FlowExecutionOutcome outcome = new FlowExecutionOutcome("finish", output); FlowExecutionResult result = FlowExecutionResult.createEndedResult("foo", outcome); EasyMock.expectLastCall().andReturn(result); EasyMock.replay(new Object[] { executor }); ModelAndView mv = controller.handleRequest(request, response); assertNull(mv); assertEquals("/springtravel/app/foo?bar=baz", response.getRedirectedUrl()); EasyMock.verify(new Object[] { executor }); } public void testHandleFlowExceptionCustomFlowHandler() throws Exception { final FlowException flowException = new FlowException("Error") { }; controller.registerFlowHandler(new FlowHandler() { public String getFlowId() { return "foo"; } public MutableAttributeMap<Object> createExecutionInputMap(HttpServletRequest request) { return null; } public String handleExecutionOutcome(FlowExecutionOutcome outcome, HttpServletRequest request, HttpServletResponse response) { return null; } public String handleException(FlowException e, HttpServletRequest request, HttpServletResponse response) { assertEquals(flowException, e); return null; } }); request.setContextPath("/springtravel"); request.setServletPath("/app"); request.setPathInfo("/foo"); request.setRequestURI("/springtravel/app/foo"); request.setMethod("GET"); executor.launchExecution("foo", null, context); EasyMock.expectLastCall().andThrow(flowException); EasyMock.replay(new Object[] { executor }); try { controller.handleRequest(request, response); fail("Should have thrown exception"); } catch (FlowException e) { assertEquals(flowException, e); } EasyMock.verify(new Object[] { executor }); } }