/*
* MockFrame2TestCase - a JUnit extension for testing Frame2 events and event
* handlers in the context of the HttpFrontController. Based on StrutsTestCase
* by Deryl Sealef This library is free software; you can redistribute it and/or
* modify it under the terms of the Apache Software License as published by the
* Apache Software Foundation; either version 1.1 of the License, or (at your
* option) any later version. This library is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Apache
* Software Foundation Licens for more details. You may view the full text here:
* http: www.apache.org/LICENSE.txt
*/
package servletunit.frame2;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.InputStream;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import junit.framework.AssertionFailedError;
import org.apache.commons.digester.Digester;
import org.junit.Before;
import org.megatome.frame2.front.Frame2ContextListener;
import org.megatome.frame2.front.HttpFrontController;
import org.megatome.frame2.log.LoggerFactory;
import servletunit.HttpServletResponseSimulator;
import servletunit.ServletContextSimulator;
// NIT: cleanup description
/**
* MockFrame2TestCase is an extension of the base JUnit testcase that provides
* additional methods to aid in testing WAM events and event handlers. It uses a
* mock object approach to simulate a servlet container, and tests the execution
* of events as they are actually run through the WAM HttpFrontController.
* WamTestCase provides methods that set up the request path, request parameters
* for event subclasses, as well as methods that can verify that the correct
* ActionForward was used and that the proper ActionError messages were
* supplied. <br>
* <br>
* <b>NOTE: </b> By default, the Struts ActionServlet will look for the file
* <code>WEB-INF/struts-config.xml</code>, so you must place the directory
* that <i>contains </i> WEB-INF in your CLASSPATH. If you would like to use an
* alternate configuration file, please see the setConfigFile() method for
* details on how this file is located.
*/
public class MockFrame2TestCase {
//HttpServletRequestSimulator request;
Frame2HttpServletRequestSimulator request;
HttpServletResponseSimulator response;
MockFrame2ServletContextSimulator context;
MockFrame2ServletConfigSimulator config;
ServletContextListener listener;
String eventPath;
boolean isInitialized;
HttpFrontController servlet;
/**
* A check that every method should run to ensure that the base class setUp
* method has been called.
*/
private void confirmSetup() {
if (!this.isInitialized) {
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."); //$NON-NLS-1$
}
}
/**
* Sets up the test fixture for this test. This method creates an instance
* of the ActionServlet, initializes it to validate forms and turn off
* debugging, and creates a mock HttpServletRequest and HttpServletResponse
* object to use in this test.
*/
@Before
public void setUp() throws Exception {
if (this.servlet == null) {
this.servlet = new HttpFrontController();
}
LoggerFactory.setType("org.megatome.frame2.log.impl.StandardLogger", //$NON-NLS-1$
getClass().getClassLoader());
this.config = new MockFrame2ServletConfigSimulator();
//request = new
// HttpServletRequestSimulator(config.getServletContext());
this.request = new Frame2HttpServletRequestSimulator(this.config
.getServletContext());
this.response = new HttpServletResponseSimulator();
this.context = (MockFrame2ServletContextSimulator)this.config
.getServletContext();
this.listener = new Frame2ContextListener();
this.isInitialized = true;
sendContextInitializedEvent(null, null);
this.servlet.init(this.config);
}
public ServletContextListener getContextListener() {
return this.listener;
}
public void sendContextInitializedEvent(String key, String value) {
if (key != null && value != null) {
this.context.setInitParameter(key, value);
}
this.listener.contextInitialized(new ServletContextEvent(this.context));
}
public void sendContextDestroyedEvent() {
this.listener.contextDestroyed(new ServletContextEvent(this.context));
}
public void sendContextInitializedEvent(String key1, String value1,
String key2, String value2) {
if (key1 != null && value1 != null) {
this.context.setInitParameter(key1, value1);
}
if (key2 != null && value2 != null) {
this.context.setInitParameter(key2, value2);
}
this.listener.contextInitialized(new ServletContextEvent(this.context));
}
/**
* Returns an HttpServletRequest object that can be used in this test.
*/
public HttpServletRequest getRequest() {
confirmSetup();
return this.request;
}
// /**
// * Returns a HttpServletRequestWrapper object that can be used
// * in this test. Note that if {@link #setRequestWrapper} has not been
// * called, this method will return an instance of
// * javax.servlet.http.HttpServletRequestWrapper.
// */
// public HttpServletRequestWrapper getRequestWrapper() {
// if (logger.isDebugEnabled())
// logger.debug("Entering getRequestWrapper()");
// init();
// if (requestWrapper == null) {
// if (logger.isDebugEnabled())
// logger.debug("Exiting getRequestWrapper()");
// return new HttpServletRequestWrapper(request);
// } else {
// if (logger.isDebugEnabled()) {
// logger.debug(
// "getRequestWrapper() : wrapper class is '" + requestWrapper.getClass() +
// "'");
// }
// if (logger.isDebugEnabled())
// logger.debug("Exiting getRequestWrapper()");
// return requestWrapper;
// }
// }
// /**
// * Set this TestCase to use a given HttpServletRequestWrapper
// * class when calling Action.perform(). Note that if this
// * method is not called, then the normal HttpServletRequest
// * object is used.
// *
// * @param wrapper an HttpServletRequestWrapper object to be
// * used when calling Action.perform().
// */
// public void setRequestWrapper(HttpServletRequestWrapper wrapper) {
// if (logger.isDebugEnabled())
// logger.debug("Entering setRequestWrapper() : wrapper = " + wrapper);
// init();
// if (wrapper == null)
// throw new IllegalArgumentException("wrapper class cannot be null!");
// else {
// if (wrapper.getRequest() == null)
// wrapper.setRequest(request);
// _requestWrapper = wrapper;
// }
// if (logger.isDebugEnabled())
// logger.debug("Exiting setRequestWrapper()");
// }
/**
* Returns an HttpServletResponse object that can be used in this test.
*/
public HttpServletResponse getResponse() {
confirmSetup();
return this.response;
}
// /**
// * Returns an HttpServletResponseWrapper object that can be used in
// * this test. Note that if {@link #setResponseWrapper} has not been
// * called, this method will return an instance of
// * javax.servlet.http.HttpServletResponseWrapper.
// */
// public HttpServletResponseWrapper getResponseWrapper() {
// if (logger.isDebugEnabled())
// logger.debug("Entering getResponseWrapper()");
// init();
// if (responseWrapper == null) {
// if (logger.isDebugEnabled())
// logger.debug("Exiting getResponseWrapper()");
// return new HttpServletResponseWrapper(response);
// } else {
// if (logger.isDebugEnabled()) {
// logger.debug(
// "getRequestWrapper() : wrapper class is '" + responseWrapper.getClass() +
// "'");
// }
// if (logger.isDebugEnabled())
// logger.debug("Exiting getResponseWrapper()");
// return responseWrapper;
// }
// }
// /**
// * Set this TestCase to use a given HttpServletResponseWrapper
// * class when calling Action.perform(). Note that if this
// * method is not called, then the normal HttpServletResponse
// * object is used.
// *
// * @param wrapper an HttpServletResponseWrapper object to be
// * used when calling Action.perform().
// */
// public void setResponseWrapper(HttpServletResponseWrapper wrapper) {
// if (logger.isDebugEnabled())
// logger.debug("Entering setResponseWrapper() : wrapper = " + wrapper);
// init();
// if (wrapper == null)
// throw new IllegalArgumentException("wrapper class cannot be null!");
// else {
// if (wrapper.getResponse() == null)
// wrapper.setResponse(response);
// _responseWrapper = wrapper;
// }
// if (logger.isDebugEnabled())
// logger.debug("Exiting setResponseWrapper()");
// }
/**
* Returns an HttpSession object that can be used in this test.
*/
public HttpSession getSession() {
confirmSetup();
return this.request.getSession(true);
}
public ServletContext getContext() {
confirmSetup();
return this.context;
}
public HttpFrontController getServlet() {
confirmSetup();
return this.servlet;
}
// /**
// * Returns the ActionServlet controller used in this
// * test.
// *
// */
// public ActionServlet getActionServlet() {
// if (logger.isDebugEnabled())
// logger.debug("Entering getActionServlet()");
// init();
// try {
// if (!servletIsInitialized) {
// if (logger.isDebugEnabled()) {
// logger.debug("getActionServlet() : intializing servlet");
// }
// this._servlet.init(config);
// servletIsInitialized = true;
// }
// } catch (ServletException e) {
// if (logger.isDebugEnabled())
// logger.debug("Error in getActionServlet()", e.getRootCause());
// throw new AssertionFailedError(e.getMessage());
// }
// if (logger.isDebugEnabled())
// logger.debug("Exiting getActionServlet()");
// return servlet;
// }
// /**
// * Sets the ActionServlet to be used in this test execution. This
// * method should only be used if you plan to use a customized
// * version different from that provided in the Struts distribution.
// */
// public void setActionServlet(ActionServlet servlet) {
// if (logger.isDebugEnabled())
// logger.debug("Entering setActionServlet() : servlet = " + servlet);
// init();
// if (servlet == null)
// throw new AssertionFailedError("Cannot set ActionServlet to null");
// this._servlet = servlet;
// if (logger.isDebugEnabled())
// logger.debug("Exiting setActionServlet()");
// servletIsInitialized = false;
// }
/**
* Executes the Action instance to be tested. This method calls the
* ActionServlet.doPost() method to execute the Action instance to be
* tested, passing along any parameters set in the HttpServletRequest
* object. It stores any results for further validation.
* @exception AssertionFailedError if there are any execution errors while
* calling Action.perform()
*/
public void doEvent() {
confirmSetup();
try {
this.servlet.doPost(this.request, this.response);
} catch (ServletException se) {
fail("Error running doEvent(): " + se.getRootCause().getClass() //$NON-NLS-1$
+ " - " + se.getRootCause().getMessage()); //$NON-NLS-1$
} catch (Exception ex) {
fail("Error running action.perform(): " + ex.getClass() + " - " //$NON-NLS-1$ //$NON-NLS-2$
+ ex.getMessage());
}
}
/**
* Adds an HttpServletRequest parameter to be used in setting up the
* ActionForm instance to be used in this test. Each parameter added should
* correspond to an attribute in the ActionForm instance used by the Action
* instance being tested.
*/
public void addRequestParameter(String parameterName, String parameterValue) {
confirmSetup();
this.request.addParameter(parameterName, parameterValue);
}
/**
* Adds an HttpServletRequest parameter that is an array of String values to
* be used in setting up the ActionForm instance to be used in this test.
* Each parameter added should correspond to an attribute in the ActionForm
* instance used by the Action instance being tested.
*/
public void addRequestParameter(String parameterName,
String[] parameterValues) {
confirmSetup();
this.request.addParameter(parameterName, parameterValues);
}
/**
* Sets the request path instructing the ActionServlet to used a particual
* ActionMapping.
* @param pathInfo the request path to be processed. This should correspond
* to a particular action mapping, as would normally appear in an
* HTML or JSP source file.
*/
public void setRequestPathInfo(String pathInfo) {
confirmSetup();
this.eventPath = stripActionPath(pathInfo);
this.request.setPathInfo(this.eventPath);
}
public void setServletPath(String pathInfo) {
confirmSetup();
this.eventPath = stripActionPath(pathInfo);
this.request.setServletPath(this.eventPath);
}
protected static String stripActionPath(String inPath) {
if (inPath == null)
return null;
String path = inPath;
int slash = path.lastIndexOf("/"); //$NON-NLS-1$
int period = path.lastIndexOf("."); //$NON-NLS-1$
if ((period >= 0) && (period > slash))
path = path.substring(0, period);
return path;
}
/**
* Sets an initialization parameter on the ActionServlet. Allows you to
* simulate an init parameter that would normally have been found in
* web.xml, but is not available while testing with mock objects.
* @param key the name of the initialization parameter
* @param value the value of the intialization parameter
*/
public void setInitParameter(String key, String value) {
confirmSetup();
this.config.setInitParameter(key, value);
this.context.setInitParameter(key, value);
}
/**
* Sets the context directory to be used with the getRealPath() methods in
* the ServletContext and HttpServletRequest API.
* @param contextDirectory a File object representing the root context
* directory for this application.
*/
public void setContextDirectory(File contextDirectory) {
confirmSetup();
this.context.setContextDirectory(contextDirectory);
}
/**
* Sets the struts configuration file for a given sub-application. This
* method can take either an absolute path, or a relative path. If an
* absolute path is supplied, the configuration file will be loaded from the
* underlying filesystem; otherwise, the ServletContext loader will be used.
* @param pathname the location of the configuration file for this
* sub-application
*/
public void setConfigFile(String pathname) {
confirmSetup();
this.config.setInitParameter("config", pathname); //$NON-NLS-1$
}
/**
* Sets the location of the web.xml configuration file to be used to set up
* the servlet context and configuration for this test. This method supports
* both init-param and context-param tags, setting the ServletConfig and
* ServletContext appropriately. This method can take either an absolute
* path, or a relative path. If an absolute path is supplied, the
* configuration file will be loaded from the underlying filesystem;
* otherwise, the ServletContext loader will be used.
*/
public void setServletConfigFile(String pathname) {
confirmSetup();
// pull in the appropriate parts of the
// web.xml file -- first the init-parameters
Digester digester = new Digester();
digester.push(this.config);
digester.setValidating(false);
digester.addCallMethod("web-app/servlet/init-param", //$NON-NLS-1$
"setInitParameter", 2); //$NON-NLS-1$
digester.addCallParam("web-app/servlet/init-param/param-name", 0); //$NON-NLS-1$
digester.addCallParam("web-app/servlet/init-param/param-value", 1); //$NON-NLS-1$
try {
InputStream input = this.context.getResourceAsStream(pathname);
if (input == null)
throw new AssertionFailedError("Invalid pathname: " + pathname); //$NON-NLS-1$
digester.parse(input);
input.close();
} catch (Exception e) {
throw new AssertionFailedError(
"Received an exception while loading web.xml - " //$NON-NLS-1$
+ e.getClass() + " : " + e.getMessage()); //$NON-NLS-1$
}
// now the context parameters..
digester = new Digester();
digester.setValidating(false);
digester.push(this.context);
digester.addCallMethod("web-app/context-param", "setInitParameter", 2); //$NON-NLS-1$ //$NON-NLS-2$
digester.addCallParam("web-app/context-param/param-name", 0); //$NON-NLS-1$
digester.addCallParam("web-app/context-param/param-value", 1); //$NON-NLS-1$
try {
InputStream input = this.context.getResourceAsStream(pathname);
if (input == null)
throw new AssertionFailedError("Invalid pathname: " + pathname); //$NON-NLS-1$
digester.parse(input);
input.close();
} catch (Exception e) {
throw new AssertionFailedError(
"Received an exception while loading web.xml - " //$NON-NLS-1$
+ e.getClass() + " : " + e.getMessage()); //$NON-NLS-1$
}
}
/**
* Returns the forward sent to RequestDispatcher.
*/
private String getActualForward() {
if (this.response.containsHeader("Location")) { //$NON-NLS-1$
return stripJSessionID(this.response.getHeader("Location")); //$NON-NLS-1$
}
try {
String strippedForward = this.request.getContextPath()
+ stripJSessionID(((ServletContextSimulator)this.config
.getServletContext())
.getRequestDispatcherSimulator().getForward());
return strippedForward;
} catch (NullPointerException npe) {
return null;
}
}
/**
* Strip ;jsessionid= <sessionid>from path.
* @return stripped path
*/
protected static String stripJSessionID(String inPath) {
if (inPath == null)
return null;
String path = inPath;
String pathCopy = path.toLowerCase();
int jsess_idx = pathCopy.indexOf(";jsessionid="); //$NON-NLS-1$
if (jsess_idx > 0) {
// Strip jsessionid from obtained path
StringBuffer buf = new StringBuffer(path);
path = buf.delete(jsess_idx, jsess_idx + 44).toString();
}
return path;
}
/**
* Verifies if the ActionServlet controller used this forward.
* @param forwardName the logical name of a forward, as defined in the
* Struts configuration file. This can either refer to a global
* forward, or one local to the ActionMapping.
* @exception AssertionFailedError if the ActionServlet controller used a
* different forward than <code>forwardName</code> after
* executing an Action object.
*/
public void verifyForward(@SuppressWarnings("unused")
String forwardName) throws AssertionFailedError {
confirmSetup();
// verifyForwardPath(
// servlet,
// eventPath,
// forwardName,
// getActualForward(),
// false,
// request,
// config.getServletContext(),
// config);
}
/**
* Verifies if the ActionServlet controller used this actual path as a
* forward.
* @param forwardPath an absolute pathname to which the request is to be
* forwarded.
* @exception AssertionFailedError if the ActionServlet controller used a
* different forward path than <code>forwardPath</code> after
* executing an Action object.
*/
public void verifyForwardPath(final String forwardPath)
throws AssertionFailedError {
confirmSetup();
String fullForwardPath = this.request.getContextPath() + forwardPath;
String actualForward = getActualForward();
if (actualForward == null) {
throw new AssertionFailedError(
"Was expecting '" //$NON-NLS-1$
+ fullForwardPath
+ "' but it appears the Action has tried to return an ActionForward that is not mapped correctly."); //$NON-NLS-1$
}
if (!(actualForward.equals(fullForwardPath)))
throw new AssertionFailedError("was expecting '" + fullForwardPath //$NON-NLS-1$
+ "' but received '" + actualForward + "'"); //$NON-NLS-1$ //$NON-NLS-2$
}
// /**
// * Verifies if the ActionServlet controller forwarded to the defined
// * input path.
// *
// * @exception AssertionFailedError if the ActionServlet controller
// * used a different forward than the defined input path after
// * executing an Action object.
// */
// public void verifyInputForward() {
// if (logger.isDebugEnabled())
// logger.debug("Entering verifyInputForward()");
// init();
// Common.verifyForwardPath(
// servlet,
// eventPath,
// null,
// getActualForward(),
// true,
// request,
// config.getServletContext(),
// config);
// if (logger.isDebugEnabled())
// logger.debug("Exiting verifyInputForward()");
// }
// /**
// * Verifies if the ActionServlet controller sent these error messages.
// * There must be an exact match between the provided error messages, and
// * those sent by the controller, in both name and number.
// *
// * @param errorNames a String array containing the error message keys
// * to be verified, as defined in the application resource properties
// * file.
// *
// * @exception AssertionFailedError if the ActionServlet controller
// * sent different error messages than those in <code>errorNames</code>
// * after executing an Action object.
// */
// public void verifyActionErrors(String[] errorNames) {
// if (logger.isDebugEnabled())
// logger.debug("Entering verifyActionErrors() : errorNames = " +
// errorNames);
// init();
// Common.verifyActionMessages(request, errorNames, Action.ERROR_KEY,
// "error");
// if (logger.isDebugEnabled())
// logger.debug("Exiting verifyActionErrors()");
// }
// /**
// * Verifies that the ActionServlet controller sent no error messages upon
// * executing an Action object.
// *
// * @exception AssertionFailedError if the ActionServlet controller
// * sent any error messages after excecuting and Action object.
// */
// public void verifyNoActionErrors() {
// if (logger.isDebugEnabled())
// logger.debug("Entering verifyNoActionErrors()");
// init();
// Common.verifyNoActionMessages(request, Action.ERROR_KEY, "error");
// if (logger.isDebugEnabled())
// logger.debug("Exiting verifyNoActionErrors()");
// }
// /**
// * Verifies if the ActionServlet controller sent these action messages.
// * There must be an exact match between the provided action messages, and
// * those sent by the controller, in both name and number.
// *
// * @param messageNames a String array containing the action message keys
// * to be verified, as defined in the application resource properties
// * file.
// *
// * @exception AssertionFailedError if the ActionServlet controller
// * sent different action messages than those in <code>messageNames</code>
// * after executing an Action object.
// */
// public void verifyActionMessages(String[] messageNames) {
// if (logger.isDebugEnabled())
// logger.debug("Entering verifyActionMessages() : messageNames = " +
// messageNames);
// init();
// Common.verifyActionMessages(request, messageNames, Globals.MESSAGE_KEY,
// "action");
// if (logger.isDebugEnabled())
// logger.debug("Exiting verifyActionMessages()");
// }
// /**
// * Verifies that the ActionServlet controller sent no action messages upon
// * executing an Action object.
// *
// * @exception AssertionFailedError if the ActionServlet controller
// * sent any action messages after excecuting and Action object.
// */
// public void verifyNoActionMessages() {
// if (logger.isDebugEnabled())
// logger.debug("Entering verifyNoActionMessages()");
// init();
// Common.verifyNoActionMessages(request, Globals.MESSAGE_KEY, "action");
// if (logger.isDebugEnabled())
// logger.debug("Exiting verifyNoActionMessages()");
// }
// /**
// * Returns the ActionForm instance stored in either the request or
// session. Note
// * that no form will be returned if the Action being tested cleans up the
// form
// * instance.
// *
// * @ return the ActionForm instance used in this test, or null if it does
// not exist.
// */
// public ActionForm getActionForm() {
// if (logger.isDebugEnabled())
// logger.debug("Entering getActionForm()");
// init();
// if (logger.isDebugEnabled())
// logger.debug("Exiting getActionForm()");
// return Common.getActionForm(servlet, eventPath, request, context);
// }
// /**
// * Sets an ActionForm instance to be used in this test. The given
// ActionForm instance
// * will be stored in the scope specified in the Struts configuration file
// (ie: request
// * or session). Note that while this ActionForm instance is passed to the
// test, Struts
// * will still control how it is used. In particular, it will call the
// ActionForm.reset()
// * method, so if you override this method in your ActionForm subclass, you
// could potentially
// * reset attributes in the form passed through this method.
// *
// * @param form the ActionForm instance to be used in this test.
// */
// public void setActionForm(ActionForm form) {
// if (logger.isDebugEnabled())
// logger.debug("Entering setActionForm() : form = " + form);
// init();
// // make sure action servlet is intialized
// Common.setActionForm(form, request, eventPath, context,
// this.getActionServlet());
// if (logger.isDebugEnabled())
// logger.debug("Exiting setActionForm()");
// }
// protected static void verifyForwardPath(
// HttpFrontController servlet,
// String actionPath,
// String forwardName,
// String actualForwardPath,
// boolean isInputPath,
// HttpServletRequest request,
// ServletContext context,
// ServletConfig config) {
//
// if ((forwardName == null) && (isInputPath)) {
// forwardName = getActionConfig(servlet, actionPath, request,
// context).getInput();
// if (forwardName == null)
// throw new AssertionFailedError("Trying to validate against an input
// mapping, but none is defined for this Action.");
// }
// if (!isInputPath) {
// ActionForward expectedForward =
// findForward(actionPath, forwardName, request, context, servlet);
// if (expectedForward == null) {
// expectedForward = servlet.findForward(forwardName);
// }
// if (expectedForward == null)
// throw new AssertionFailedError(
// "Cannot find forward '"
// + forwardName
// + "' - it is possible that it is not mapped correctly.");
// forwardName = expectedForward.getPath();
//
// }
// if (!forwardName.startsWith("/"))
// forwardName = "/" + forwardName;
//
// forwardName = request.getContextPath() + forwardName;
// if (actualForwardPath == null) {
// throw new AssertionFailedError(
// "Was expecting '"
// + forwardName
// + "' but it appears the Action has tried to return an ActionForward that
// is not mapped correctly.");
// }
// if (!forwardName.equals(stripJSessionID(actualForwardPath)))
// throw new AssertionFailedError(
// "was expecting '" + forwardName + "' but received '" + actualForwardPath
// + "'");
// }
protected void setUserRole(String role) {
this.request.setUserRole(role);
}
protected void setRemoteUser(String login) {
this.request.setRemoteUser(login);
}
}