001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.pluto.testsuite.test;
018:
019: import org.apache.commons.logging.Log;
020: import org.apache.commons.logging.LogFactory;
021: import org.apache.pluto.testsuite.TestConfig;
022: import org.apache.pluto.testsuite.PortletTest;
023: import org.apache.pluto.testsuite.TestResult;
024: import org.apache.pluto.testsuite.TestResults;
025:
026: import javax.portlet.PortletResponse;
027: import javax.portlet.PortletRequest;
028: import javax.portlet.PortletContext;
029: import javax.portlet.PortletConfig;
030: import javax.portlet.PortletSession;
031: import java.lang.reflect.InvocationTargetException;
032: import java.lang.reflect.Method;
033: import java.lang.reflect.Modifier;
034: import java.util.ArrayList;
035: import java.util.Iterator;
036: import java.util.List;
037: import java.util.Map;
038: import java.util.HashMap;
039:
040: /**
041: *
042: */
043: public abstract class AbstractReflectivePortletTest implements
044: PortletTest {
045:
046: /** Logger. */
047: private static final Log LOG = LogFactory
048: .getLog(AbstractReflectivePortletTest.class);
049:
050: private Map initParameters;
051: private TestConfig config;
052:
053: // PortletTest Impl --------------------------------------------------------
054:
055: public void init(TestConfig config) {
056: this .config = config;
057: this .initParameters = config.getInitParameters();
058: }
059:
060: /**
061: * Returns the render parameters that will be set into the render request.
062: * The default implementation just returns an empty Map object. This method
063: * may be overwritten by some concrete test to provide test-specific render
064: * parameters.
065: * @param request the portlet request.
066: * @return an empty Map object.
067: */
068: public Map getRenderParameters(PortletRequest request) {
069: return new HashMap();
070: }
071:
072: public TestConfig getConfig() {
073: return config;
074: }
075:
076: /**
077: * Returns the test suite name. The test suite name is the portlet test
078: * class name without package name prefix.
079: * @return the test suite name.
080: */
081: public String getTestSuiteName() {
082: String className = getClass().getName();
083: int index = className.lastIndexOf(".");
084: if (index >= 0 && index < className.length() - 1) {
085: return className.substring(index + 1);
086: } else {
087: return className;
088: }
089: }
090:
091: /**
092: * Invoke test methods using java reflection. All 'check*' methods are
093: * invoked and test results are saved into <code>TestResults</code> object.
094: * @param config the portlet config.
095: * @param context the portlet context.
096: * @param request the portlet request.
097: * @param response the portlet response.
098: * @return the test results including several TestResult instances.
099: */
100: public TestResults doTest(PortletConfig config,
101: PortletContext context, PortletRequest request,
102: PortletResponse response) {
103: TestResults results = new TestResults(getTestSuiteName());
104:
105: for (Iterator it = getCheckMethods().iterator(); it.hasNext();) {
106: Method method = (Method) it.next();
107: debugWithName("Invoking test method: " + method.getName());
108: try {
109: TestResult result = invoke(method, config, context,
110: request, response);
111: if (result.getName() == null) {
112: result.setName(method.getName());
113: }
114: results.add(result);
115: debugWithName("Result: "
116: + result.getReturnCodeAsString());
117: } catch (Throwable th) {
118: String message = "Error invoking " + method.getName()
119: + " (" + th.getClass().getName() + "): "
120: + th.getMessage();
121: errorWithName(message, th);
122: TestResult result = new TestResult();
123: result.setName(method.getName());
124: result.setReturnCode(TestResult.FAILED);
125: result.setResultMessage(message);
126: results.add(result);
127: }
128: }
129:
130: return results;
131: }
132:
133: // Protected Methods -------------------------------------------------------
134:
135: protected Map getInitParameters() {
136: return initParameters;
137: }
138:
139: // Private Methods ---------------------------------------------------------
140:
141: private void debugWithName(String message) {
142: if (LOG.isDebugEnabled()) {
143: LOG.debug("Test [" + getTestSuiteName() + "]: " + message);
144: }
145: }
146:
147: private void errorWithName(String message, Throwable cause) {
148: if (LOG.isErrorEnabled()) {
149: LOG.error("Test [" + getTestSuiteName() + "]: " + message,
150: cause);
151: }
152: }
153:
154: /**
155: * Returns check methods to run as tests using java reflection.
156: * The following rules are applied to select check methods:
157: * <ul>
158: * <li>methods declared in this class or inherited from super class</li>
159: * <li>methods with modifier 'public' or 'protected', but not 'abstract'</li>
160: * <li>methods that starts with <code>check</code></li>
161: * </ul>
162: * @return a list of check methods.
163: */
164: private List getCheckMethods() {
165: List checkMethods = new ArrayList();
166: for (Class clazz = getClass(); clazz != null
167: && AbstractReflectivePortletTest.class
168: .isAssignableFrom(clazz); clazz = clazz
169: .getSuperclass()) {
170: // debugWithName("Checking class: " + clazz.getName());
171: Method[] methods = clazz.getDeclaredMethods();
172: for (int i = 0; i < methods.length; i++) {
173: int mod = methods[i].getModifiers();
174: if ((Modifier.isPublic(mod) || Modifier
175: .isProtected(mod))
176: && !Modifier.isAbstract(mod)
177: && methods[i].getName().startsWith("check")) {
178: // debugWithName(" - got check method: " + methods[i].getName());
179: checkMethods.add(methods[i]);
180: }
181: }
182: }
183: return checkMethods;
184: }
185:
186: /**
187: * Invokes the test method ('<code>check*</code>') by preparing method
188: * parameters. A test method may accept the following types of parameters:
189: * <ul>
190: * <li><code>javax.portlet.PortletConfig</code></li>
191: * <li><code>javax.portlet.PortletContext</code></li>
192: * <li><code>javax.portlet.PortletRequest</code></li>
193: * <li><code>javax.portlet.PortletResponse</code></li>
194: * <li><code>javax.portlet.PortletSession</code></li>
195: * </ul>
196: */
197: private TestResult invoke(Method method, PortletConfig config,
198: PortletContext context, PortletRequest request,
199: PortletResponse response) throws IllegalAccessException,
200: InvocationTargetException {
201:
202: Class[] paramTypes = method.getParameterTypes();
203: Object[] paramValues = new Object[paramTypes.length];
204:
205: for (int i = 0; i < paramTypes.length; i++) {
206: if (paramTypes[i].equals(PortletConfig.class)) {
207: paramValues[i] = config;
208: } else if (paramTypes[i].equals(PortletContext.class)) {
209: paramValues[i] = context;
210: } else if (paramTypes[i].equals(PortletRequest.class)) {
211: paramValues[i] = request;
212: } else if (paramTypes[i].equals(PortletResponse.class)) {
213: paramValues[i] = response;
214: } else if (paramTypes[i].equals(PortletSession.class)) {
215: paramValues[i] = request.getPortletSession();
216: }
217: }
218: TestResult result = (TestResult) method.invoke(this ,
219: paramValues);
220: return result;
221: }
222:
223: // Object Methods ----------------------------------------------------------
224:
225: /**
226: * Override of toString() that prints out names and values of variables.
227: * @see java.lang.Object#toString()
228: */
229: public String toString() {
230: StringBuffer buffer = new StringBuffer();
231: buffer.append(getClass().getName());
232: buffer.append("[initParameters=").append(initParameters);
233: buffer.append(";config=").append(config).append("]");
234: return buffer.toString();
235: }
236: }
|