001: /*
002: * Copyright 2007 The Kuali Foundation
003: *
004: * Licensed under the Educational Community License, Version 1.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.opensource.org/licenses/ecl1.php
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.kuali.rice.test;
017:
018: import java.util.ArrayList;
019: import java.util.LinkedList;
020: import java.util.List;
021: import java.util.ListIterator;
022:
023: import javax.xml.namespace.QName;
024:
025: import org.apache.log4j.Logger;
026: import org.junit.After;
027: import org.junit.Before;
028: import org.kuali.rice.config.Config;
029: import org.kuali.rice.config.SimpleConfig;
030: import org.kuali.rice.core.Core;
031: import org.kuali.rice.lifecycle.Lifecycle;
032: import org.kuali.rice.resourceloader.SpringResourceLoader;
033:
034: /**
035: * Useful superclass for all Workflow test cases. Handles setup of test
036: * utilities and a test environment. Configures the Spring test environment
037: * providing a template method for custom context files in test mode. Also
038: * provides a template method for running custom transactional setUp. Tear down
039: * handles automatic tear down of objects created inside the test environment.
040: *
041: * @author Kuali Rice Team (kuali-rice@googlegroups.com)
042: * @since 0.9
043: */
044: public abstract class RiceTestCase extends LoggableTestCase {
045:
046: private static final Logger LOG = Logger
047: .getLogger(RiceTestCase.class);
048:
049: protected static boolean SUITE_LIFE_CYCLES_RAN = false;
050:
051: private List<Lifecycle> perTestLifeCycles = new LinkedList<Lifecycle>();
052:
053: private List<Lifecycle> suiteLifeCycles = new LinkedList<Lifecycle>();
054:
055: private List<String> reports = new ArrayList<String>();
056:
057: private SpringResourceLoader testHarnessSpringResourceLoader;
058:
059: @Before
060: public void setUp() throws Exception {
061: try {
062: beforeRun();
063: final long initTime = System.currentTimeMillis();
064: this .perTestLifeCycles = getPerTestLifecycles();
065: this .suiteLifeCycles = getSuiteLifecycles();
066:
067: startLifecycles(this .perTestLifeCycles);
068:
069: if (!SUITE_LIFE_CYCLES_RAN) {
070: startLifecycles(this .suiteLifeCycles);
071: SUITE_LIFE_CYCLES_RAN = true;
072: }
073: report("Time to start all Lifecycles: "
074: + (System.currentTimeMillis() - initTime));
075: } catch (Throwable e) {
076: e.printStackTrace();
077: throw new RuntimeException(e);
078: }
079: }
080:
081: /**
082: * maven will set this property and find resources from the config based on
083: * it. This makes eclipse testing work because we have to put the basedir in
084: * our config files in order to find things when testing from maven
085: *
086: */
087: protected void setBaseDirSystemProperty(String moduleBaseDir) {
088: if (System.getProperty("basedir") == null) {
089: System.setProperty("basedir", System
090: .getProperty("user.dir")
091: + "/" + moduleBaseDir);
092: }
093: }
094:
095: protected void setModuleName(String moduleName) {
096: if (System.getProperty("module.name") == null) {
097: System.setProperty("module.name", moduleName);
098: }
099: }
100:
101: @After
102: public void tearDown() throws Exception {
103: stopLifecycles(this .perTestLifeCycles);
104: afterRun();
105: }
106:
107: protected void beforeRun() {
108: System.out
109: .println("##############################################################");
110: System.out.println("# Starting test "
111: + getClass().getSimpleName() + "...");
112: System.out.println("# " + dumpMemory());
113: System.out
114: .println("##############################################################");
115: }
116:
117: protected void afterRun() {
118: System.out
119: .println("##############################################################");
120: System.out.println("# ...finished test "
121: + getClass().getSimpleName());
122: System.out.println("# " + dumpMemory());
123: for (final String report : this .reports) {
124: System.out.println("# " + report);
125: }
126: System.out
127: .println("##############################################################\n\n\n");
128: }
129:
130: protected void startLifecycles(List<Lifecycle> lifecycles)
131: throws Exception {
132: for (Lifecycle lifecycle : lifecycles) {
133: lifecycle.start();
134: }
135: }
136:
137: protected void stopLifecycles(List<Lifecycle> lifecycles)
138: throws Exception {
139: final ListIterator<Lifecycle> iter = lifecycles.listIterator();
140: while (iter.hasNext()) {
141: iter.next();
142: }
143: while (iter.hasPrevious()) {
144: final Lifecycle lifeCycle = iter.previous();
145: try {
146: lifeCycle.stop();
147: } catch (Exception e) {
148: LOG
149: .warn(
150: "Failed to shutdown one of the lifecycles!",
151: e);
152: }
153: }
154: }
155:
156: /**
157: *
158: * @return Lifecycles ran every test run
159: */
160: protected List<Lifecycle> getPerTestLifecycles() {
161: LinkedList<Lifecycle> lifeCycles = new LinkedList<Lifecycle>();
162: lifeCycles.add(new Lifecycle() {
163: boolean started = false;
164:
165: public boolean isStarted() {
166: return this .started;
167: }
168:
169: public void start() throws Exception {
170: setModuleName(getModuleName());
171: setBaseDirSystemProperty(getModuleName());
172: Config config = getTestHarnessConfig();
173: Core.init(config);
174: this .started = true;
175: }
176:
177: public void stop() throws Exception {
178: this .started = false;
179: }
180: });
181: lifeCycles.add(getTestHarnessSpringResourceLoader());
182: lifeCycles.add(new Lifecycle() {
183: boolean started = false;
184:
185: public boolean isStarted() {
186: return this .started;
187: }
188:
189: public void start() throws Exception {
190: TestHarnessServiceLocator
191: .setContext(getTestHarnessSpringResourceLoader()
192: .getContext());
193: this .started = true;
194: }
195:
196: public void stop() throws Exception {
197: this .started = false;
198: }
199: });
200: lifeCycles.add(new DerbyDBCreationLifecycle(
201: getDerbySQLFileLocation()));
202: lifeCycles.add(new ClearDatabaseLifecycle(getTablesToClear(),
203: getTablesNotToClear()));
204: return lifeCycles;
205: }
206:
207: protected List<String> getTablesToClear() {
208: return new ArrayList<String>();
209: }
210:
211: protected List<String> getTablesNotToClear() {
212: return new ArrayList<String>();
213: }
214:
215: /**
216: *
217: * @return Lifecycles run once during the suite
218: */
219: protected List<Lifecycle> getSuiteLifecycles() {
220: return new LinkedList<Lifecycle>();
221: }
222:
223: protected void report(final String report) {
224: this .reports.add(report);
225: }
226:
227: protected String dumpMemory() {
228: final long total = Runtime.getRuntime().totalMemory();
229: final long free = Runtime.getRuntime().freeMemory();
230: final long max = Runtime.getRuntime().maxMemory();
231: return "[Memory] max: " + max + ", total: " + total
232: + ", free: " + free;
233: }
234:
235: public SpringResourceLoader getTestHarnessSpringResourceLoader() {
236: if (testHarnessSpringResourceLoader == null) {
237: testHarnessSpringResourceLoader = new SpringResourceLoader(
238: new QName("TestHarnessSpringContext"),
239: "classpath:TestHarnessSpringBeans.xml");
240: }
241: return testHarnessSpringResourceLoader;
242: }
243:
244: protected Config getTestHarnessConfig() throws Exception {
245: Config config = new SimpleConfig(getConfigLocations(), System
246: .getProperties());
247: config.parseConfig();
248: return config;
249: }
250:
251: /**
252: * @return List of config locations to add to this tests config location.
253: */
254: protected abstract List<String> getConfigLocations();
255:
256: /**
257: * same as the module directory in the project.
258: *
259: * @return name of module that the tests located
260: */
261: protected abstract String getModuleName();
262:
263: /**
264: * Note: We may want to make this more automagical and base this off of
265: * convention from the module name Typical return value
266: * "classpath:db/derby/testharness.sql"
267: *
268: * @return location of sql file containing ddl for a derby db to be ran
269: * before start up.
270: */
271: protected abstract String getDerbySQLFileLocation();
272:
273: }
|