1   //  StrutsTestCase - a JUnit extension for testing Struts actions
2   //  within the context of the ActionServlet.
3   //  Copyright (C) 2002 Deryl Seale
4   //
5   //  This library is free software; you can redistribute it and/or
6   //  modify it under the terms of the Apache Software License as
7   //  published by the Apache Software Foundation; either version 1.1
8   //  of the License, or (at your option) any later version.
9   //
10  //  This library is distributed in the hope that it will be useful,
11  //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  //  Apache Software Foundation Licens for more details.
14  //
15  //  You may view the full text here: http://www.apache.org/LICENSE.txt
16  
17  package servletunit.struts;
18  
19  import junit.framework.AssertionFailedError;
20  import junit.framework.TestCase;
21  import org.apache.commons.digester.Digester;
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  import org.apache.struts.Globals;
25  import org.apache.struts.action.ActionForm;
26  import org.apache.struts.action.ActionServlet;
27  import servletunit.HttpServletRequestSimulator;
28  import servletunit.HttpServletResponseSimulator;
29  import servletunit.ServletConfigSimulator;
30  import servletunit.ServletContextSimulator;
31  
32  import javax.servlet.http.*;
33  import java.io.File;
34  import java.io.InputStream;
35  import java.net.URL;
36  
37  /**
38   * MockStrutsTestCase is an extension of the base JUnit testcase that
39   * provides additional methods to aid in testing Struts Action
40   * objects.  It uses a mock object approach to simulate a servlet
41   * container, and tests the execution of Action objects as they
42   * are actually run through the Struts ActionServlet.  MockStrutsTestCase
43   * provides methods that set up the request path, request parameters
44   * for ActionForm subclasses, as well as methods that can verify
45   * that the correct ActionForward was used and that the proper
46   * ActionError messages were supplied.
47   *
48   *<br><br>
49   *<b>NOTE:</b> By default, the Struts ActionServlet will look for the
50   * file <code>WEB-INF/struts-config.xml</code>, so you must place
51   * the directory that <i>contains</i> WEB-INF in your CLASSPATH.  If
52   * you would like to use an alternate configuration file, please see
53   * the setConfigFile() method for details on how this file is located.
54   */
55  public class MockStrutsTestCase extends TestCase {
56  
57      protected ActionServlet actionServlet;
58      protected HttpServletRequestSimulator request;
59      protected HttpServletResponseSimulator response;
60      protected HttpServletRequestWrapper requestWrapper;
61      protected HttpServletResponseWrapper responseWrapper;
62      protected ServletContextSimulator context;
63      protected ServletConfigSimulator config;
64      protected String actionPath;
65      protected boolean isInitialized = false;
66      protected boolean actionServletIsInitialized = false;
67      protected boolean requestPathSet = false;
68  
69      /**
70       * The set of public identifiers, and corresponding resource names, for
71       * the versions of the configuration file DTDs that we know about.  There
72       * <strong>MUST</strong> be an even number of Strings in this list!
73       */
74      protected String registrations[] = {
75          "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN",
76          "/org/apache/struts/resources/web-app_2_2.dtd",
77          "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",
78          "/org/apache/struts/resources/web-app_2_3.dtd"
79      };
80  
81  
82      protected static Log logger = LogFactory.getLog(MockStrutsTestCase.class);
83  
84      /**
85       * Default constructor.
86       */
87      public MockStrutsTestCase() {
88          super();
89      }
90  
91      /**
92       * Constructor that takes test name parameter, for backwards compatibility with older versions on JUnit.
93       */
94      public MockStrutsTestCase(String testName) {
95          super(testName);
96      }
97  
98      /**
99       * A check that every method should run to ensure that the
100      * base class setUp method has been called.
101      */
102     private void init() {
103         if (!isInitialized)
104             throw new AssertionFailedError("You are overriding the setUp() method without calling super.setUp().  You must call the superclass setUp() method in your TestCase subclass to ensure proper initialization.");
105     }
106 
107     /**
108      * Sets up the test fixture for this test.  This method creates
109      * an instance of the ActionServlet, initializes it to validate
110      * forms and turn off debugging, and creates a mock HttpServletRequest
111      * and HttpServletResponse object to use in this test.
112      */
113     protected void setUp() throws Exception {
114         if (logger.isDebugEnabled())
115             logger.debug("Entering");
116         if (actionServlet == null)
117             actionServlet = new ActionServlet();
118         config = new ServletConfigSimulator();
119         request = new HttpServletRequestSimulator(config.getServletContext());
120         response = new HttpServletResponseSimulator();
121         context = (ServletContextSimulator) config.getServletContext();
122         requestWrapper = null;
123         responseWrapper = null;
124         isInitialized = true;
125         if (logger.isDebugEnabled())
126             logger.debug("Exiting");
127     }
128 
129     protected void tearDown() throws Exception {
130         ActionServlet servlet = getActionServlet();
131         servlet.destroy();
132         setActionServlet(servlet);
133     }
134 
135     /**
136      * Returns an HttpServletRequest object that can be used in
137      * this test.
138      */
139     public HttpServletRequest getRequest() {
140         if (logger.isDebugEnabled())
141             logger.debug("Entering");
142         init();
143         if (logger.isDebugEnabled())
144             logger.debug("Exiting");
145         return this.request;
146     }
147 
148     /**
149      * Returns a HttpServletRequestWrapper object that can be used
150      * in this test. Note that if {@link #setRequestWrapper} has not been
151      * called, this method will return an instance of
152      * javax.servlet.http.HttpServletRequestWrapper.
153      */
154     public HttpServletRequestWrapper getRequestWrapper() {
155         if (logger.isDebugEnabled())
156             logger.debug("Entering");
157         init();
158         if (requestWrapper == null) {
159             if (logger.isDebugEnabled())
160                 logger.debug("Exiting");
161             return new HttpServletRequestWrapper(this.request);
162         } else {
163             if (logger.isDebugEnabled()) {
164                 logger.debug("wrapper class is '" + requestWrapper.getClass() + "'");
165             }
166             if (logger.isDebugEnabled())
167                 logger.debug("Exiting");
168             return requestWrapper;
169         }
170     }
171 
172     /**
173      * Set this TestCase to use a given HttpServletRequestWrapper
174      * class when calling Action.execute().  Note that if this
175      * method is not called, then the normal HttpServletRequest
176      * object is used.
177      *
178      * @param wrapper an HttpServletRequestWrapper object to be
179      * used when calling Action.execute().
180      */
181     public void setRequestWrapper(HttpServletRequestWrapper wrapper) {
182         if (logger.isDebugEnabled())
183             logger.debug("Entering - wrapper = " + wrapper);
184         init();
185         if (wrapper == null)
186             throw new IllegalArgumentException("wrapper class cannot be null!");
187         else {
188             if (wrapper.getRequest() == null)
189                 wrapper.setRequest(this.request);
190             this.requestWrapper = wrapper;
191         }
192         if (logger.isDebugEnabled())
193             logger.debug("Exiting");
194     }
195 
196     /**
197      * Clears all request parameters previously set.
198      */
199     public void clearRequestParameters() {
200         if (logger.isTraceEnabled())
201             logger.trace("Entering");
202         this.request.getParameterMap().clear();
203 
204         // also, clear out the redirect header if it's there.
205         response.removeHeader("Location");
206         if (logger.isTraceEnabled())
207             logger.trace("Exiting");
208     }
209 
210     /**
211      * Returns an HttpServletResponse object that can be used in
212      * this test.
213      */
214     public HttpServletResponse getResponse() {
215         if (logger.isDebugEnabled())
216             logger.debug("Entering");
217         init();
218         if (logger.isDebugEnabled())
219             logger.debug("Exiting");
220         return this.response;
221     }
222 
223     /**
224      * Returns an HttpServletResponseWrapper object that can be used in
225      * this test.  Note that if {@link #setResponseWrapper} has not been
226      * called, this method will return an instance of
227      * javax.servlet.http.HttpServletResponseWrapper.
228      */
229     public HttpServletResponseWrapper getResponseWrapper() {
230         if (logger.isDebugEnabled())
231             logger.debug("Entering");
232         init();
233         if (responseWrapper == null) {
234             if (logger.isDebugEnabled())
235                 logger.debug("Exiting");
236             return new HttpServletResponseWrapper(this.response);
237         } else {
238             if (logger.isDebugEnabled()) {
239                 logger.debug("wrapper class is '" + responseWrapper.getClass() + "'");
240             }
241             if (logger.isDebugEnabled())
242                 logger.debug("Exiting");
243             return responseWrapper;
244         }
245     }
246 
247     /**
248      * Set this TestCase to use a given HttpServletResponseWrapper
249      * class when calling Action.execute().  Note that if this
250      * method is not called, then the normal HttpServletResponse
251      * object is used.
252      *
253      * @param wrapper an HttpServletResponseWrapper object to be
254      * used when calling Action.execute().
255      */
256     public void setResponseWrapper(HttpServletResponseWrapper wrapper) {
257         if (logger.isDebugEnabled())
258             logger.debug("Entering - wrapper = " + wrapper);
259         init();
260         if (wrapper == null)
261             throw new IllegalArgumentException("wrapper class cannot be null!");
262         else {
263             if (wrapper.getResponse() == null)
264                 wrapper.setResponse(this.response);
265             this.responseWrapper = wrapper;
266         }
267         if (logger.isDebugEnabled())
268             logger.debug("Exiting");
269     }
270 
271     /**
272      * Returns the mock HttpServletRequest object used in this test.  This allows
273      * access to methods for setting up test preconditions that are otherwise
274      * unavailable through the normal Servlet API.
275      */
276     public HttpServletRequestSimulator getMockRequest() {
277         if (logger.isTraceEnabled())
278             logger.trace("Entering");
279         init();
280         if (logger.isTraceEnabled())
281             logger.trace("Exiting");
282         return this.request;
283     }
284 
285     /**
286      * Returns the mock HttpServletResponse object used in this test.  This allows
287      * access to methods for setting up test preconditions that are otherwise
288      * unavailable through the normal Servlet API.
289      */
290     public HttpServletResponseSimulator getMockResponse() {
291         if (logger.isTraceEnabled())
292             logger.trace("Entering");
293         init();
294         if (logger.isTraceEnabled())
295             logger.trace("Exiting");
296         return this.response;
297     }
298 
299     /**
300      * Returns an HttpSession object that can be used in this
301      * test.
302      */
303     public HttpSession getSession() {
304         if (logger.isDebugEnabled())
305             logger.debug("Entering");
306         init();
307         if (logger.isDebugEnabled())
308             logger.debug("Exiting");
309         return this.request.getSession(true);
310     }
311 
312     /**
313      * Returns the ActionServlet controller used in this
314      * test.
315      *
316      */
317     public ActionServlet getActionServlet() {
318         if (logger.isDebugEnabled())
319             logger.debug("Entering");
320         init();
321         try {
322             if (!actionServletIsInitialized) {
323                 if (logger.isDebugEnabled()) {
324                     logger.debug("intializing actionServlet");
325                 }
326                 this.actionServlet.init(config);
327                 actionServletIsInitialized = true;
328             }
329         } catch (Exception e) {
330             logger.error("Error initializing action servlet",e);
331             if(e.getMessage().equals("java.lang.NullPointerException")){
332                 String message = "Error initializing action servlet: Unable to find /WEB-INF/web.xml.  "
333                                + "TestCase is running from " + System.getProperty("user.dir") + " directory.  "
334                                + "Context directory ";
335                 if(this.context.getContextDirectory()==null){
336                     message += "has not been set.  Try calling setContextDirectory() with a relative or absolute path";
337                 }else{
338                     message = message + "is " + this.context.getContextDirectory().getAbsolutePath();
339                 }
340                 message = message + ".  /WEB-INF/web.xml must be found under the context directory, "
341                         + "the directory the test case is running from, or in the classpath.";
342                 fail(message);
343             }else{
344                 throw new AssertionFailedError(e.getMessage());
345             }
346         }
347         if (logger.isDebugEnabled())
348             logger.debug("Exiting");
349         return actionServlet;
350     }
351 
352     /**
353      * Sets the ActionServlet to be used in this test execution.  This
354      * method should only be used if you plan to use a customized
355      * version different from that provided in the Struts distribution.
356      */
357     public void setActionServlet(ActionServlet servlet) {
358         if (logger.isDebugEnabled())
359             logger.debug("Entering - servlet = " + servlet);
360         init();
361         if (servlet == null)
362             throw new AssertionFailedError("Cannot set ActionServlet to null");
363         this.actionServlet = servlet;
364         if (logger.isDebugEnabled())
365             logger.debug("Exiting");
366         actionServletIsInitialized = false;
367     }
368 
369     /**
370      * Executes the Action instance to be tested.  This method
371      * calls the ActionServlet.doPost() method to execute the
372      * Action instance to be tested, passing along any parameters
373      * set in the HttpServletRequest object.  It stores any results
374      * for further validation.
375      *
376      * @exception AssertionFailedError if there are any execution
377      * errors while calling Action.execute()
378      *
379      */
380     public void actionPerform() {
381         if (logger.isDebugEnabled())
382             logger.debug("Entering");
383         if(!this.requestPathSet){
384             throw new IllegalStateException("You must call setRequestPathInfo() prior to calling actionPerform().");
385         }
386         init();
387         HttpServletRequest request = this.request;
388         HttpServletResponse response = this.response;
389         if (this.requestWrapper != null)
390             request = this.requestWrapper;
391         if (this.responseWrapper != null)
392             response = this.responseWrapper;
393         try {
394             this.getActionServlet().doPost(request,response);
395         }catch (NullPointerException npe) {
396                 String message = "A NullPointerException was thrown.  This may indicate an error in your ActionForm, or "
397                                + "it may indicate that the Struts ActionServlet was unable to find struts config file.  "
398                                + "TestCase is running from " + System.getProperty("user.dir") + " directory.  "
399                                + "Context directory ";
400                 if(this.context.getContextDirectory()==null){
401                     message += "has not been set.  Try calling setContextDirectory() with a relative or absolute path";
402                 }else{
403                     message = message + "is " + this.context.getContextDirectory().getAbsolutePath();
404                 }
405                 message = message + ".  struts config file must be found under the context directory, "
406                         + "the directory the test case is running from, or in the classpath.";
407                 throw new ExceptionDuringTestError(message, npe);
408         }catch(Exception e){
409                 throw new ExceptionDuringTestError("An uncaught exception was thrown during actionExecute()", e);
410         }
411         if (logger.isDebugEnabled())
412             logger.debug("Exiting");
413     }
414 
415     /**
416      * Adds an HttpServletRequest parameter to be used in setting up the
417      * ActionForm instance to be used in this test.  Each parameter added
418      * should correspond to an attribute in the ActionForm instance used
419      * by the Action instance being tested.
420      */
421     public void addRequestParameter(String parameterName, String parameterValue)
422     {
423         if (logger.isDebugEnabled())
424             logger.debug("Entering - parameterName = " + parameterName + ", parameterValue = " + parameterValue);
425         init();
426         this.request.addParameter(parameterName,parameterValue);
427         if (logger.isDebugEnabled())
428             logger.debug("Exiting");
429     }
430 
431     /**
432      * Adds an HttpServletRequest parameter that is an array of String values
433      * to be used in setting up the ActionForm instance to be used in this test.
434      * Each parameter added should correspond to an attribute in the ActionForm
435      * instance used by the Action instance being tested.
436      */
437     public void addRequestParameter(String parameterName, String[] parameterValues)
438     {
439         if (logger.isDebugEnabled())
440             logger.debug("Entering - parameterName = " + parameterName + ", parameteValue = " + parameterValues);
441         init();
442         this.request.addParameter(parameterName,parameterValues);
443         if (logger.isDebugEnabled())
444             logger.debug("Exiting");
445     }
446 
447     /**
448      * Sets the request path instructing the ActionServlet to used a
449      * particual ActionMapping.
450      *
451      * @param pathInfo the request path to be processed.  This should
452      * correspond to a particular action mapping, as would normally
453      * appear in an HTML or JSP source file.
454      */
455     public void setRequestPathInfo(String pathInfo) {
456         if (logger.isDebugEnabled())
457             logger.debug("Entering - pathInfo = " + pathInfo);
458         init();
459         this.setRequestPathInfo("",pathInfo);
460         if (logger.isDebugEnabled())
461             logger.debug("Exiting");
462     }
463 
464     /**
465      * Sets the request path instructing the ActionServlet to used a
466      * particual ActionMapping.  Also sets the ServletPath property
467      * on the request.
468      *
469      * @param moduleName the name of the Struts sub-application with
470      * which this request is associated, or null if it is the default
471      * application.
472      * @param pathInfo the request path to be processed.  This should
473      * correspond to a particular action mapping, as would normally
474      * appear in an HTML or JSP source file.  If this request is part
475      * of a sub-application, the module name should not appear in the
476      * request path.
477      */
478     public void setRequestPathInfo(String moduleName, String pathInfo) {
479         if (logger.isDebugEnabled())
480             logger.debug("Entering - moduleName = " + moduleName + ", pathInfo = " + pathInfo);
481         init();
482         this.actionPath = Common.stripActionPath(pathInfo);
483         if (moduleName != null) {
484             if (!moduleName.equals("")) {
485                 if (!moduleName.startsWith("/"))
486                     moduleName = "/" + moduleName;
487                 if (!moduleName.endsWith("/"))
488                     moduleName = moduleName + "/";
489             }
490             if (logger.isDebugEnabled()) {
491                 logger.debug("setting request attribute - name = " + Common.INCLUDE_SERVLET_PATH + ", value = " + moduleName);
492             }
493             this.request.setAttribute(Common.INCLUDE_SERVLET_PATH, moduleName);
494         }
495         this.request.setPathInfo(actionPath);
496         this.requestPathSet = true;
497         if (logger.isDebugEnabled())
498             logger.debug("Exiting");
499     }
500 
501     /**
502      * Sets an initialization parameter on the
503      * ActionServlet.  Allows you to simulate an init parameter
504      * that would normally have been found in web.xml,
505      * but is not available while testing with mock objects.
506      * @param key the name of the initialization parameter
507      * @param value the value of the intialization parameter
508      */
509     public void setInitParameter(String key, String value){
510         if (logger.isDebugEnabled())
511             logger.debug("Entering - key = " + key + ", value = " + value);
512         init();
513         config.setInitParameter(key, value);
514         actionServletIsInitialized = false;
515         if (logger.isDebugEnabled())
516             logger.debug("Exiting");
517     }
518 
519     /**
520      * Sets the context directory to be used with the getRealPath() methods in
521      * the ServletContext and HttpServletRequest API.
522      * @param contextDirectory a File object representing the root context directory
523      * for this application.
524      */
525     public void setContextDirectory(File contextDirectory) {
526         if (logger.isDebugEnabled())
527             logger.debug("Entering - contextDirectory = " + contextDirectory);
528         init();
529         context.setContextDirectory(contextDirectory);
530         actionServletIsInitialized = false;
531         if (logger.isDebugEnabled())
532             logger.debug("Exiting");
533     }
534 
535     /**
536      * Sets the location of the Struts configuration file for the default module.
537      * This method can take either an absolute path, or a relative path.  If an
538      * absolute path is supplied, the configuration file will be loaded from the
539      * underlying filesystem; otherwise, the ServletContext loader will be used.
540      */
541     public void setConfigFile(String pathname) {
542         if (logger.isDebugEnabled())
543             logger.debug("Entering - pathName = " + pathname);
544         init();
545         setConfigFile(null,pathname);
546         if (logger.isDebugEnabled())
547             logger.debug("Exiting");
548     }
549 
550     /**
551      * Sets the struts configuration file for a given sub-application. This method
552      * can take either an absolute path, or a relative path.  If an absolute path
553      * is supplied, the configuration file will be loaded from the underlying
554      * filesystem; otherwise, the ServletContext loader will be used.
555      *
556      * @param moduleName the name of the sub-application, or null if this is the default application
557      * @param pathname the location of the configuration file for this sub-application
558      */
559     public void setConfigFile(String moduleName, String pathname) {
560         if (logger.isDebugEnabled())
561             logger.debug("Entering - moduleName = " + moduleName + ", pathname =" + pathname);
562         init();
563         if (moduleName == null)
564             this.config.setInitParameter("config",pathname);
565         else
566             this.config.setInitParameter("config/" + moduleName,pathname);
567         actionServletIsInitialized = false;
568         if (logger.isDebugEnabled())
569             logger.debug("Exiting");
570     }
571 
572     /**
573      * Sets the location of the web.xml configuration file to be used
574      * to set up the servlet context and configuration for this test.
575      * This method supports both init-param and context-param tags,
576      * setting the ServletConfig and ServletContext appropriately.
577      * This method can take either an absolute path, or a relative path.  If an
578      * absolute path is supplied, the configuration file will be loaded from the
579      * underlying filesystem; otherwise, the ServletContext loader will be used.
580      */
581     public void setServletConfigFile(String pathname) {
582         if (logger.isDebugEnabled())
583             logger.debug("Entering - pathname = " + pathname);
584         init();
585 
586         // pull in the appropriate parts of the
587         // web.xml file -- first the init-parameters
588         Digester digester = new Digester();
589         digester.push(this.config);
590         digester.setValidating(true);
591         digester.addCallMethod("web-app/servlet/init-param", "setInitParameter", 2);
592         digester.addCallParam("web-app/servlet/init-param/param-name", 0);
593         digester.addCallParam("web-app/servlet/init-param/param-value", 1);
594         try {
595             for (int i = 0; i < registrations.length; i += 2) {
596                 URL url = context.getResource(registrations[i + 1]);
597                 if (url != null)
598                     digester.register(registrations[i], url.toString());
599             }
600             InputStream input = context.getResourceAsStream(pathname);
601             if(input==null)
602                 throw new AssertionFailedError("Invalid pathname: " + pathname);
603             digester.parse(input);
604             input.close();
605         } catch (Exception e) {
606             throw new AssertionFailedError("Received an exception while loading web.xml - " + e.getClass() + " : " + e.getMessage());
607         }
608 
609         // now the context parameters..
610         digester = new Digester();
611         digester.setValidating(true);
612         digester.push(this.context);
613         digester.addCallMethod("web-app/context-param", "setInitParameter", 2);
614         digester.addCallParam("web-app/context-param/param-name", 0);
615         digester.addCallParam("web-app/context-param/param-value", 1);
616         try {
617             for (int i = 0; i < registrations.length; i += 2) {
618                 URL url = context.getResource(registrations[i + 1]);
619                 if (url != null)
620                     digester.register(registrations[i], url.toString());
621             }
622             InputStream input = context.getResourceAsStream(pathname);
623             if(input==null)
624                 throw new AssertionFailedError("Invalid pathname: " + pathname);
625             digester.parse(input);
626             input.close();
627         } catch (Exception e) {
628             throw new AssertionFailedError("Received an exception while loading web.xml - " + e.getClass() + " : " + e.getMessage());
629         }
630         actionServletIsInitialized = false;
631         if (logger.isDebugEnabled())
632             logger.debug("Exiting");
633     }
634 
635     /**
636      * Returns the forward sent to RequestDispatcher.
637      */
638     protected String getActualForward() {
639         if (logger.isDebugEnabled())
640             logger.debug("Entering");
641         if (response.containsHeader("Location")) {
642             return Common.stripJSessionID(response.getHeader("Location"));
643         } else
644             try  {
645                 String strippedForward = request.getContextPath() + Common.stripJSessionID(((ServletContextSimulator) config.getServletContext()).getRequestDispatcherSimulator().getForward());
646                 if (logger.isDebugEnabled()) {
647                     logger.debug("stripped forward and added context path - " + strippedForward);
648                 }
649                 if (logger.isDebugEnabled())
650                     logger.debug("Exiting");
651                 return strippedForward;
652             } catch (NullPointerException npe) {
653                 if (logger.isDebugEnabled()) {
654                     logger.debug("caught NullPointerException - returning null",npe);
655                 }
656                 return null;
657             }
658     }
659 
660     /**
661      * Verifies if the ActionServlet controller used this forward.
662      *
663      * @param forwardName the logical name of a forward, as defined
664      * in the Struts configuration file.  This can either refer to a
665      * global forward, or one local to the ActionMapping.
666      *
667      * @exception AssertionFailedError if the ActionServlet controller
668      * used a different forward than <code>forwardName</code> after
669      * executing an Action object.
670      */
671     public void verifyForward(String forwardName) throws AssertionFailedError {
672         if (logger.isDebugEnabled())
673             logger.debug("Entering - forwardName = " + forwardName);
674         init();
675         Common.verifyForwardPath(actionPath,forwardName,getActualForward(),false,request,config.getServletContext(),config);
676         if (logger.isDebugEnabled())
677             logger.debug("Exiting");
678     }
679 
680     /**
681      * Verifies if the ActionServlet controller used this actual path
682      * as a forward.
683      *
684      * @param forwardPath an absolute pathname to which the request
685      * is to be forwarded.
686      *
687      * @exception AssertionFailedError if the ActionServlet controller
688      * used a different forward path than <code>forwardPath</code> after
689      * executing an Action object.
690      */
691     public void verifyForwardPath(String forwardPath) throws AssertionFailedError {
692         if (logger.isDebugEnabled())
693             logger.debug("Entering - forwardPath = " + forwardPath);
694         init();
695         String actualForward = getActualForward();
696         if ((actualForward == null) && (forwardPath == null)) {
697             // actions can send null forwards, which is fine.
698             return;
699         }
700 
701         forwardPath = request.getContextPath() + forwardPath;
702 
703         if (actualForward == null) {
704             if (logger.isDebugEnabled()) {
705                 logger.debug("actualForward is null - this usually means it is not mapped properly.");
706             }
707             throw new AssertionFailedError("Was expecting '" + forwardPath + "' but it appears the Action has tried to return an ActionForward that is not mapped correctly.");
708         }
709         if (logger.isDebugEnabled()) {
710             logger.debug("expected forward = '" + forwardPath + "' - actual forward = '" + actualForward + "'");
711         }
712         if (!(actualForward.equals(forwardPath)))
713             throw new AssertionFailedError("was expecting '" + forwardPath + "' but received '" + actualForward + "'");
714         if (logger.isDebugEnabled())
715             logger.debug("Exiting");
716     }
717 
718     /**
719      * Verifies if the ActionServlet controller forwarded to the defined
720      * input path.
721      *
722      * @exception AssertionFailedError if the ActionServlet controller
723      * used a different forward than the defined input path after
724      * executing an Action object.
725      */
726     public void verifyInputForward() {
727         if (logger.isDebugEnabled())
728             logger.debug("Entering");
729         init();
730         Common.verifyForwardPath(actionPath,null,getActualForward(),true,request,config.getServletContext(),config);
731         if (logger.isDebugEnabled())
732             logger.debug("Exiting");
733     }
734 
735     /**
736      * Verifies that the ActionServlet controller used this forward and Tiles definition.
737      *
738      * @param forwardName the logical name of a forward, as defined
739      * in the Struts configuration file.  This can either refer to a
740      * global forward, or one local to the ActionMapping.
741      *
742      * @param definitionName the name of a Tiles definition, as defined
743      * in the Tiles configuration file.
744      *
745      * @exception AssertionFailedError if the ActionServlet controller
746      * used a different forward or tiles definition than those given after
747      * executing an Action object.
748      */
749     public void verifyTilesForward(String forwardName, String definitionName) {
750         if (logger.isTraceEnabled())
751             logger.trace("Entering - forwardName=" + forwardName + ", definitionName=" + definitionName);
752         init();
753         Common.verifyTilesForward(actionPath,forwardName,definitionName,false,request,config.getServletContext(),config);
754         if (logger.isTraceEnabled())
755             logger.trace("Exiting");
756     }
757 
758     /**
759      * Verifies that the ActionServlet controller forwarded to the defined
760      * input Tiles definition.
761      *
762      * @param definitionName the name of a Tiles definition, as defined
763      * in the Tiles configuration file.
764      *
765      * @exception AssertionFailedError if the ActionServlet controller
766      * used a different forward than the defined input path after
767      * executing an Action object.
768      */
769     public void verifyInputTilesForward(String definitionName) {
770         if (logger.isTraceEnabled())
771             logger.trace("Entering - definitionName=" + definitionName);
772         init();
773         Common.verifyTilesForward(actionPath,null,definitionName,true,request,config.getServletContext(),config);
774         if (logger.isTraceEnabled())
775             logger.trace("Exiting");
776     }
777 
778     /**
779      * Verifies if the ActionServlet controller sent these error messages.
780      * There must be an exact match between the provided error messages, and
781      * those sent by the controller, in both name and number.
782      *
783      * @param errorNames a String array containing the error message keys
784      * to be verified, as defined in the application resource properties
785      * file.
786      *
787      * @exception AssertionFailedError if the ActionServlet controller
788      * sent different error messages than those in <code>errorNames</code>
789      * after executing an Action object.
790      */
791 
792     public void verifyActionErrors(String[] errorNames) {
793         if (logger.isDebugEnabled())
794             logger.debug("errorNames = " + errorNames);
795         init();
796         Common.verifyActionMessages(request,errorNames,Globals.ERROR_KEY,"error");
797         if (logger.isDebugEnabled())
798             logger.debug("Exiting");
799     }
800 
801 
802     /**
803      * Verifies that the ActionServlet controller sent no error messages upon
804      * executing an Action object.
805      *
806      * @exception AssertionFailedError if the ActionServlet controller
807      * sent any error messages after excecuting and Action object.
808      */
809     public void verifyNoActionErrors() {
810         if (logger.isDebugEnabled())
811             logger.debug("Entering");
812         init();
813         Common.verifyNoActionMessages(request,Globals.ERROR_KEY,"error");
814         if (logger.isDebugEnabled())
815             logger.debug("Exiting");
816     }
817 
818     /**
819      * Verifies if the ActionServlet controller sent these action messages.
820      * There must be an exact match between the provided action messages, and
821      * those sent by the controller, in both name and number.
822      *
823      * @param messageNames a String array containing the action message keys
824      * to be verified, as defined in the application resource properties
825      * file.
826      *
827      * @exception AssertionFailedError if the ActionServlet controller
828      * sent different action messages than those in <code>messageNames</code>
829      * after executing an Action object.
830      */
831     public void verifyActionMessages(String[] messageNames) {
832         if (logger.isDebugEnabled())
833             logger.debug("Entering - messageNames = " + messageNames);
834         init();
835         Common.verifyActionMessages(request,messageNames,Globals.MESSAGE_KEY,"action");
836         if (logger.isDebugEnabled())
837             logger.debug("Exiting");
838     }
839 
840     /**
841      * Verifies that the ActionServlet controller sent no action messages upon
842      * executing an Action object.
843      *
844      * @exception AssertionFailedError if the ActionServlet controller
845      * sent any action messages after excecuting and Action object.
846      */
847     public void verifyNoActionMessages() {
848         if (logger.isDebugEnabled())
849             logger.debug("Entering");
850         init();
851         Common.verifyNoActionMessages(request,Globals.MESSAGE_KEY,"action");
852         if (logger.isDebugEnabled())
853             logger.debug("Exiting");
854     }
855 
856     /**
857      * Returns the ActionForm instance stored in either the request or session.  Note
858      * that no form will be returned if the Action being tested cleans up the form
859      * instance.
860      *
861      * @ return the ActionForm instance used in this test, or null if it does not exist.
862      */
863     public ActionForm getActionForm() {
864         if (logger.isDebugEnabled())
865             logger.debug("Entering");
866         init();
867         if (logger.isDebugEnabled())
868             logger.debug("Exiting");
869         return Common.getActionForm(actionPath,request,context);
870     }
871 
872     /**
873      * Sets an ActionForm instance to be used in this test.  The given ActionForm instance
874      * will be stored in the scope specified in the Struts configuration file (ie: request
875      * or session).  Note that while this ActionForm instance is passed to the test, Struts
876      * will still control how it is used.  In particular, it will call the ActionForm.reset()
877      * method, so if you override this method in your ActionForm subclass, you could potentially
878      * reset attributes in the form passed through this method.
879      *
880      * @param form the ActionForm instance to be used in this test.
881      */
882     public void setActionForm(ActionForm form) {
883         if (logger.isDebugEnabled())
884             logger.debug("Entering - form = " + form);
885         init();
886         // make sure action servlet is intialized
887         getActionServlet();
888         Common.setActionForm(form,request,actionPath,context);
889         if (logger.isDebugEnabled())
890             logger.debug("Exiting");
891     }
892 
893 
894 
895 
896 }
897