001: /* ====================================================================
002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
003: *
004: * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by Jcorporate Ltd.
021: * (http://www.jcorporate.com/)."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. "Jcorporate" and product names such as "Expresso" must
026: * not be used to endorse or promote products derived from this
027: * software without prior written permission. For written permission,
028: * please contact info@jcorporate.com.
029: *
030: * 5. Products derived from this software may not be called "Expresso",
031: * or other Jcorporate product names; nor may "Expresso" or other
032: * Jcorporate product names appear in their name, without prior
033: * written permission of Jcorporate Ltd.
034: *
035: * 6. No product derived from this software may compete in the same
036: * market space, i.e. framework, without prior written permission
037: * of Jcorporate Ltd. For written permission, please contact
038: * partners@jcorporate.com.
039: *
040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
051: * SUCH DAMAGE.
052: * ====================================================================
053: *
054: * This software consists of voluntary contributions made by many
055: * individuals on behalf of the Jcorporate Ltd. Contributions back
056: * to the project(s) are encouraged when you make modifications.
057: * Please send them to support@jcorporate.com. For more information
058: * on Jcorporate Ltd. and its products, please see
059: * <http://www.jcorporate.com/>.
060: *
061: * Portions of this software are based upon other open source
062: * products and are subject to their respective licenses.
063: */
064:
065: package com.jcorporate.expresso.services.test;
066:
067: import com.jcorporate.expresso.core.ExpressoConstants;
068: import com.jcorporate.expresso.core.controller.Controller;
069: import com.jcorporate.expresso.core.controller.ControllerException;
070: import com.jcorporate.expresso.core.controller.ControllerResponse;
071: import com.jcorporate.expresso.core.db.DBConnectionPool;
072: import com.jcorporate.expresso.core.misc.ConfigManager;
073: import com.jcorporate.expresso.core.misc.CookieUtil;
074: import com.jcorporate.expresso.core.misc.StringDOMParser;
075: import org.apache.cactus.ServletTestCase;
076: import org.apache.cactus.WebRequest;
077: import org.apache.cactus.WebResponse;
078: import org.apache.log4j.Category;
079: import org.apache.log4j.Logger;
080: import org.apache.struts.action.ActionForm;
081: import org.apache.struts.action.ActionForward;
082: import org.apache.struts.action.ActionMapping;
083: import org.apache.struts.action.ActionServlet;
084: import org.apache.struts.config.ActionConfig;
085: import org.apache.struts.util.RequestUtils;
086: import org.apache.xpath.XPathAPI;
087: import org.w3c.dom.Document;
088: import org.w3c.dom.NodeList;
089:
090: import javax.servlet.ServletException;
091: import javax.servlet.http.HttpSession;
092: import java.io.IOException;
093: import java.net.HttpURLConnection;
094:
095: /**
096: * Base class for testing controllers. Provides an integration with Expresso,
097: * JUnit and Cactus
098: *
099: * @author Michael Rimov
100: * @version $Revision: 1.17 $ $Date: 2004/11/17 20:48:22 $
101: */
102: public class ControllerTestCase extends ServletTestCase {
103: private String theClass = null;
104: private Logger log = Logger.getLogger(ControllerTestCase.class);
105: private String theState = null;
106: boolean isInitialized = false;
107:
108: /**
109: * Instantiates the ControllerTestCase.
110: *
111: * @param testName the name of the test. Usually handed down by the framework
112: * @param controllerName The classname of the controller that we're testing.
113: * @throws Exception if something happens in the system initialization or potentially
114: * if the controller name passed doesn't map to a real class
115: */
116: public ControllerTestCase(String testName, String controllerName)
117: throws Exception {
118: super (testName);
119: TestSystemInitializer.setUp();
120: theClass = controllerName;
121:
122: //Check to make sure that the controllername is correct. Will initialize
123: //later, but this way the test case doesn't get off to even a start without
124: //the correct name.
125: Class.forName(controllerName);
126: }
127:
128: /**
129: * Instantiates a Controller Test Case
130: *
131: * @param testName the name of the test. Usually handed down by the framework
132: * @param controllerClass The class of the controller to test
133: */
134: public ControllerTestCase(String testName, Class controllerClass)
135: throws Exception {
136: super (testName);
137: TestSystemInitializer.setUp();
138: theClass = controllerClass.getName();
139: }
140:
141: /**
142: * returns a controller test case Log4j Category for your own easy logging
143: * without having to do special initialization etc.
144: *
145: * @return a log4j category that you can log to.
146: */
147: protected Category getLog() {
148: return log;
149: }
150:
151: /**
152: * Uses the default setup that a blank database has the security of
153: * Admin User = Admin
154: * Admin Password = Blank
155: */
156: public void logIn(WebRequest theRequest) throws Exception {
157: this .logIn(theRequest, "Admin", "");
158: }
159:
160: /**
161: * Allows special capabilities of logging in using a specially defined username
162: * and password.
163: */
164: public void logIn(WebRequest theRequest, String userName,
165: String password) throws Exception {
166: String encryptedPassword;
167:
168: if (password == null || password.length() == 0) {
169: encryptedPassword = "NONE";
170: } else {
171: encryptedPassword = CookieUtil.cookieEncode(password);
172: }
173:
174: String encryptedUserName = CookieUtil.cookieEncode(userName);
175: theRequest.addCookie("UserName", encryptedUserName);
176: theRequest.addCookie("Password", encryptedPassword);
177: theRequest.addCookie("db", CookieUtil
178: .cookieEncode(TestSystemInitializer.getTestContext()));
179: }
180:
181: /**
182: * Called to set the appropriate states for the controller Also makes sure
183: * that parameters are set up so that the controller responds in unprocessed
184: * XML, and not standard HTML
185: */
186: public void setupParameters(String state, WebRequest request) {
187: theState = state;
188: request.addParameter("style", "xml");
189: request.addParameter("xsl", "none");
190: request.addParameter(Controller.STATE_PARAM_KEY, state);
191: }
192:
193: /**
194: * parses the xml into an appropriate DOM document
195: *
196: * @deprecated
197: */
198: public Document parseResponse(WebResponse response)
199: throws Exception {
200: try {
201: int responseCode = response.getConnection()
202: .getResponseCode();
203:
204: if (responseCode != HttpURLConnection.HTTP_OK) {
205: fail("Failed to get OK Response code. Got "
206: + Integer.toString(response.getConnection()
207: .getResponseCode()) + " instead");
208: }
209:
210: String s = response.getText();
211: assertTrue("Some Real Content Returned", response
212: .getConnection().getContentLength() > 4);
213:
214: StringDOMParser sdom = new StringDOMParser();
215: Document d = sdom.parseString(s);
216: assertTrue("Reponse Returned Valid XML Document", d != null);
217:
218: return d;
219: } catch (java.io.IOException ioe) {
220: log.error("IOException parsing response", ioe);
221: fail("IOException Parsing Reponse");
222:
223: return null;
224: }
225: }
226:
227: /**
228: * Build a ControllerResponse given an XML DOM document
229: *
230: * @param d The DOM document to parse. Root node must be controller-response
231: * @deprecated
232: */
233: public ControllerResponse buildControllerResponse(Document d) {
234: ControllerResponse cr = null;
235:
236: try {
237: cr = ControllerResponse.fromXML(d);
238: } catch (ControllerException ce) {
239: log.error("ControllerException parsing response", ce);
240: }
241:
242: assertTrue("Built a valid controller response object",
243: cr != null);
244:
245: return cr;
246: }
247:
248: /**
249: * Takes the connection handed out by the framework in the endXXXX() methods
250: * and builds a full Controller Response document out of it.
251: *
252: * @deprecated
253: */
254: public ControllerResponse buildControllerResponse(
255: WebResponse theConnection) throws Exception {
256: Document d = parseResponse(theConnection);
257: assertTrue("XML Document Returned", d != null);
258:
259: NodeList nl = getNodes(d, "controller-response");
260: assertTrue("controller-response node exists",
261: nl.getLength() > 0);
262:
263: return buildControllerResponse(d);
264: }
265:
266: /**
267: * Run the target controller. Requires querying the struts framework to find
268: * out the controller, runs the controller, and then forwards the results
269: * to the XML servlet for formatting.
270: *
271: * @since Expresso 3.1
272: */
273: public ControllerResponse controllerProcess()
274: throws ServletException, IOException, Exception {
275: try {
276: ActionServlet servlet = new ActionServlet();
277: servlet.init(config);
278:
279: ActionConfig actionConfig = ConfigManager.getActionConfig(
280: theClass, theState);
281: ActionForm form = RequestUtils.createActionForm(request,
282: (ActionMapping) actionConfig, actionConfig
283: .getModuleConfig(), servlet);
284: if (form != null) {
285: if ("request".equals(actionConfig.getScope())) {
286: request.setAttribute(actionConfig.getAttribute(),
287: form);
288: } else {
289: HttpSession session = request.getSession();
290: session.setAttribute(actionConfig.getAttribute(),
291: form);
292: }
293: }
294:
295: Controller controller = null;
296:
297: try {
298: controller = ConfigManager.getControllerFactory()
299: .getController(theClass);
300: } catch (ControllerException ce) {
301: log.error("ControllerException " + theClass, ce);
302: throw new ServletException(ce);
303: }
304: try {
305: if (log.isDebugEnabled()) {
306: log.debug("forwarding to class: "
307: + controller.getClass().getName());
308: }
309:
310: ActionForward forward = controller.execute(
311: (ActionMapping) actionConfig, form, request,
312: response);
313:
314: //null forward may be desired if a custom response had been set
315: //
316: if (forward == null) {
317: return null;
318: }
319:
320: assertTrue("ERROR: Redirected To Error Page. ",
321: !(forward.getName().equals("error")));
322:
323: ControllerResponse res = null;
324:
325: try {
326: res = (ControllerResponse) request
327: .getAttribute(ExpressoConstants.CONTROLLER_RESPONSE_KEY);
328: } catch (ClassCastException cce) {
329: fail("Request Attribute Controller.RESPONSE_KEY was not a ControllerResponse Class");
330: }
331: if (res == null) {
332: fail("Error: Controller returned a null controller response");
333: }
334:
335: return res;
336: } catch (NullPointerException npe) {
337: log.error("Null Pointer Exception", npe);
338: throw npe;
339: }
340: } finally {
341:
342: //We also need to stop the job queue and start it at the beginning
343: //of the test, but we don't have that ability yet.
344: DBConnectionPool dbcp = DBConnectionPool
345: .getInstance(TestSystemInitializer.getTestContext());
346: dbcp.disconnectAll();
347: }
348: }
349:
350: /**
351: * Returns a DOM NodeList given the xpath expression and the document given.
352: * Simply wrapper
353: *
354: * @deprecated
355: */
356: public NodeList getNodes(Document d, String xpath) {
357: NodeList nl = null;
358:
359: try {
360: nl = XPathAPI.selectNodeList(d, xpath);
361: } catch (javax.xml.transform.TransformerException trex) {
362: log.error("Error performing transformation", trex);
363: }
364:
365: return nl;
366: }
367: }
|