001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/test-harness/tags/sakai_2-4-1/src/java/org/sakaiproject/test/SakaiTestBase.java $
003: * $Id: SakaiTestBase.java 19678 2006-12-18 20:30:01Z jholtzman@berkeley.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2005, 2006 The Regents of the University of California
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.test;
021:
022: import java.io.File;
023: import java.io.FileFilter;
024: import java.io.FileInputStream;
025: import java.lang.reflect.InvocationHandler;
026: import java.lang.reflect.Method;
027: import java.lang.reflect.Proxy;
028: import java.net.URL;
029: import java.net.URLClassLoader;
030: import java.util.ArrayList;
031: import java.util.Arrays;
032: import java.util.List;
033: import java.util.PropertyResourceBundle;
034:
035: import org.apache.commons.logging.Log;
036: import org.apache.commons.logging.LogFactory;
037:
038: import junit.framework.TestCase;
039:
040: /**
041: * An extension of JUnit's TestCase that launches the Sakai component manager.
042: * Extend this class to run tests in a simulated Sakai environment.
043: *
044: * <p>
045: * <strong>NOTE:</strong>
046: * Starting the component manager is an expensive operation, since it loads all
047: * of the service implementations in the system, including database connection
048: * pools, hibernate mappings, etc. To run a test suite, please collect all tests
049: * into a single class rather than running a variety of individual test cases.
050: * See {@link org.sakaiproject.test.SakaiIntegrationTest} for an example.
051: * </p>
052: *
053: * @author <a href="mailto:jholtzman@berkeley.edu">Josh Holtzman</a>
054: *
055: */
056: public abstract class SakaiTestBase extends TestCase {
057: private static final Log log = LogFactory
058: .getLog(SakaiTestBase.class);
059: protected static Object compMgr;
060:
061: /**
062: * Initialize the component manager once for all tests, and log in as admin.
063: */
064: protected static void oneTimeSetup() throws Exception {
065: if (compMgr == null) {
066: // Find the sakai home dir
067: String tomcatHome = getTomcatHome();
068: String sakaiHome = tomcatHome + File.separatorChar
069: + "sakai" + File.separatorChar;
070: String componentsDir = tomcatHome + "components/";
071:
072: // Set the system properties needed by the sakai component manager
073: System.setProperty("sakai.home", sakaiHome);
074: System.setProperty("sakai.components.root", componentsDir);
075:
076: log.debug("Starting the component manager");
077:
078: // Add the sakai jars to the current classpath. Note: We are limited to using the sun jvm now
079: URL[] sakaiUrls = getJarUrls(new String[] {
080: tomcatHome + "common/endorsed/",
081: tomcatHome + "common/lib/",
082: tomcatHome + "shared/lib/" });
083: URLClassLoader appClassLoader = (URLClassLoader) Thread
084: .currentThread().getContextClassLoader();
085: Method addMethod = URLClassLoader.class.getDeclaredMethod(
086: "addURL", new Class[] { URL.class });
087: addMethod.setAccessible(true);
088: for (int i = 0; i < sakaiUrls.length; i++) {
089: addMethod.invoke(appClassLoader,
090: new Object[] { sakaiUrls[i] });
091: }
092:
093: Class clazz = Class
094: .forName("org.sakaiproject.component.cover.ComponentManager");
095: compMgr = clazz.getDeclaredMethod("getInstance",
096: (Class[]) null).invoke((Object[]) null,
097: (Object[]) null);
098:
099: log.debug("Finished starting the component manager");
100: }
101: }
102:
103: /**
104: * Close the component manager when the tests finish.
105: */
106: public static void oneTimeTearDown() {
107: //SessionManager.getCurrentSession().invalidate();
108: if (compMgr != null) {
109: try {
110: Method closeMethod = compMgr.getClass().getMethod(
111: "close", new Class[0]);
112: closeMethod.invoke(compMgr, new Object[0]);
113: } catch (Exception e) {
114: log.error(e);
115: }
116: }
117: }
118:
119: /**
120: * Fetches the "maven.tomcat.home" property from the maven build.properties
121: * file located in the user's $HOME directory.
122: *
123: * @return
124: * @throws Exception
125: */
126: private static String getTomcatHome() throws Exception {
127: String testTomcatHome = System.getProperty("test.tomcat.home");
128: if (testTomcatHome != null && testTomcatHome.length() > 0) {
129: log.debug("Using tomcat home: " + testTomcatHome);
130: return testTomcatHome;
131: } else {
132: String homeDir = System.getProperty("user.home");
133: File file = new File(homeDir + File.separatorChar
134: + "build.properties");
135: FileInputStream fis = new FileInputStream(file);
136: PropertyResourceBundle rb = new PropertyResourceBundle(fis);
137: String tomcatHome = rb.getString("maven.tomcat.home");
138: log.debug("Tomcat home = " + tomcatHome);
139: return tomcatHome;
140: }
141: }
142:
143: /**
144: * Builds an array of file URLs from a directory path.
145: *
146: * @param dirPath
147: * @return
148: * @throws Exception
149: */
150: private static URL[] getJarUrls(String dirPath) throws Exception {
151: File dir = new File(dirPath);
152: File[] jars = dir.listFiles(new FileFilter() {
153: public boolean accept(File pathname) {
154: if (pathname.getName().startsWith("xml-apis")) {
155: return false;
156: }
157: return true;
158: }
159: });
160: URL[] urls = new URL[jars.length];
161: for (int i = 0; i < jars.length; i++) {
162: urls[i] = jars[i].toURL();
163: }
164: return urls;
165: }
166:
167: private static URL[] getJarUrls(String[] dirPaths) throws Exception {
168: List jarList = new ArrayList();
169:
170: // Add all of the tomcat jars
171: for (int i = 0; i < dirPaths.length; i++) {
172: jarList.addAll(Arrays.asList(getJarUrls(dirPaths[i])));
173: }
174:
175: URL[] urlArray = new URL[jarList.size()];
176: jarList.toArray(urlArray);
177: return urlArray;
178: }
179:
180: /**
181: * Convenience method to get a service bean from the Sakai component manager.
182: *
183: * @param beanId The id of the service
184: *
185: * @return The service, or null if the ID is not registered
186: */
187: protected static final Object getService(String beanId) {
188: try {
189: Method getMethod = compMgr.getClass().getMethod("get",
190: new Class[] { String.class });
191: return getMethod.invoke(compMgr, new Object[] { beanId });
192: } catch (Exception e) {
193: log.error(e);
194: return null;
195: }
196: }
197:
198: /**
199: * Convenience method to create a somewhat unique site id for testing. Useful
200: * in tests that need to create a site to run tests upon.
201: *
202: * @return A string suitable for using as a site id.
203: */
204: protected String generateSiteId() {
205: return "site-" + getClass().getName() + "-"
206: + Math.floor(Math.random() * 100000);
207: }
208:
209: /**
210: * Returns a dynamic proxy for a service interface. Useful for testing with
211: * customized service implementations without needing to write custom stubs.
212: *
213: * @param clazz The service interface class
214: * @param handler The invocation handler that defines how the dynamic proxy should behave
215: *
216: * @return The dynamic proxy to use as a collaborator
217: */
218: public static final Object getServiceProxy(Class clazz,
219: InvocationHandler handler) {
220: return Proxy.newProxyInstance(Thread.currentThread()
221: .getContextClassLoader(), new Class[] { clazz },
222: handler);
223: }
224: }
|