001 /*
002 * Copyright 2005-2007 The Kuali Foundation
003 *
004 *
005 * Licensed under the Educational Community License, Version 2.0 (the "License"); you may not use this file except in
006 * compliance with the License. You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS
011 * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
012 * language governing permissions and limitations under the License.
013 */
014 package org.kuali.rice.kew.test;
015
016 import java.io.InputStream;
017 import java.util.ArrayList;
018 import java.util.List;
019
020 import org.kuali.rice.core.config.Config;
021 import org.kuali.rice.core.config.ConfigContext;
022 import org.kuali.rice.core.lifecycle.BaseLifecycle;
023 import org.kuali.rice.core.lifecycle.Lifecycle;
024 import org.kuali.rice.core.web.jetty.JettyServer;
025 import org.kuali.rice.kew.batch.KEWXmlDataLoader;
026 import org.kuali.rice.kew.exception.WorkflowRuntimeException;
027 import org.kuali.rice.kew.service.KEWServiceLocator;
028 import org.kuali.rice.kew.util.KEWConstants;
029 import org.kuali.rice.kim.service.KIMServiceLocator;
030 import org.kuali.rice.kns.util.GlobalVariables;
031 import org.kuali.rice.kns.util.MessageMap;
032 import org.kuali.rice.test.ClearDatabaseLifecycle;
033 import org.kuali.rice.test.RiceInternalSuiteDataTestCase;
034 import org.kuali.rice.test.SQLDataLoader;
035 import org.springframework.transaction.support.TransactionTemplate;
036
037 /**
038 * Useful superclass for all KEW test cases. Handles setup of test utilities and
039 * a test environment. Configures the Spring test environment providing a
040 * template method for custom context files in test mode. Also provides a
041 * template method for running custom transactional setUp. Tear down handles
042 * automatic tear down of objects created inside the test environment.
043 */
044 public abstract class KEWTestCase extends RiceInternalSuiteDataTestCase {
045
046 /**
047 * This is the "bootstrap", aka Rice client, Spring beans file that the KEW
048 * test harness will load
049 */
050 private static final String DEFAULT_KEW_BOOTSTRAP_SPRING_FILE = "classpath:org/kuali/rice/kew/config/TestKEWSpringBeans.xml";
051
052 @Override
053 protected String getModuleName() {
054 return TestUtils.getModuleName();
055 }
056
057 /**
058 * Default implementation does nothing. Subclasses should override this
059 * method if they want to perform setup work inside of a database
060 * transaction.
061 */
062 protected void setUpAfterDataLoad() throws Exception {
063 // override
064 }
065
066 protected void loadTestData() throws Exception {
067 // override this to load your own test data
068 }
069
070 protected TransactionTemplate getTransactionTemplate() {
071 return TestUtilities.getTransactionTemplate();
072 }
073
074 /**
075 * Override the RiceTestCase setUpInternal in order to set a system property
076 * beforehand.
077 *
078 * @see org.kuali.rice.test.RiceTestCase#setUpInternal()
079 */
080 @Override
081 protected void setUpInternal() throws Exception {
082 System.setProperty(KEWConstants.BOOTSTRAP_SPRING_FILE,
083 getKEWBootstrapSpringFile());
084 super.setUpInternal();
085 }
086
087 /**
088 * Initiates loading of per-test data
089 */
090 @Override
091 protected void loadPerTestData() throws Exception {
092 final long t1 = System.currentTimeMillis();
093
094 loadDefaultTestData();
095
096 final long t2 = System.currentTimeMillis();
097 report("Time to load default test data: " + (t2 - t1));
098
099 loadTestData();
100
101 final long t3 = System.currentTimeMillis();
102 report("Time to load test-specific test data: " + (t3 - t2));
103
104 setUpAfterDataLoad();
105
106 final long t4 = System.currentTimeMillis();
107 report("Time to run test-specific setup: " + (t4 - t3));
108 }
109
110 /**
111 * Returns the "bootstrap", aka Rice client, Spring beans file that the KEW
112 * test harness will load. KEW test cases can override this to provide an
113 * alternative bootstrap spring file. Currently only one file is supported,
114 * so one must override this file and then import the core file.
115 *
116 * @return the "bootstrap", aka Rice client, Spring beans file that the KEW
117 * test harness will load
118 */
119 protected String getKEWBootstrapSpringFile() {
120 return DEFAULT_KEW_BOOTSTRAP_SPRING_FILE;
121 }
122
123 /**
124 * Override the standard per-test lifecycles to prepend
125 * ClearDatabaseLifecycle and ClearCacheLifecycle
126 *
127 * @see org.kuali.rice.test.RiceTestCase#getPerTestLifecycles()
128 */
129 @Override
130 protected List<Lifecycle> getPerTestLifecycles() {
131 List<Lifecycle> lifecycles = new ArrayList<Lifecycle>();
132 lifecycles.add(new ClearDatabaseLifecycle(getPerTestTablesToClear(),
133 getPerTestTablesNotToClear()));
134 lifecycles.add(new ClearCacheLifecycle());
135 lifecycles.addAll(super.getPerTestLifecycles());
136 return lifecycles;
137 }
138
139 /**
140 * Override the suite lifecycles to avoid the ClearDatabaseLifecycle (which
141 * we do on a per-test basis, as above) and to add on a JettyServer
142 * lifecycle
143 *
144 * @see org.kuali.rice.test.RiceTestCase#getSuiteLifecycles()
145 */
146 @Override
147 protected List<Lifecycle> getSuiteLifecycles() {
148
149 List<Lifecycle> lifeCycles = super.getSuiteLifecycles();
150 lifeCycles.add( buildJettyServer(getJettyServerPort(), getJettyServerContextName(), getJettyServerRelativeWebappRoot()));
151 lifeCycles.add(new InitializeGRL());
152 lifeCycles.add(new BaseLifecycle() {
153 public void start() throws Exception {
154 KEWXmlDataLoader.loadXmlClassLoaderResource(getClass(), "DefaultSuiteTestData.xml");
155 super.start();
156 }
157 });
158 return lifeCycles;
159 }
160
161 @Override
162 protected void loadSuiteTestData() throws Exception {
163 super.loadSuiteTestData();
164 new SQLDataLoader(
165 "classpath:org/kuali/rice/kew/test/DefaultSuiteTestData.sql", ";")
166 .runSql();
167 }
168
169 protected JettyServer buildJettyServer(int port, String contextName, String relativeWebappRoot) {
170 JettyServer server = new JettyServer(port, contextName, relativeWebappRoot);
171 server.setFailOnContextFailure(true);
172 server.setTestMode(true);
173 return server;
174 }
175
176 /*
177 * Checks to see if a Jetty server is runningneeds to be randomly generated and then made available to subsequent
178 * tests
179 */
180 protected int getJettyServerPort() {
181 Config cfgCtx = null;
182 try {
183 cfgCtx = getTestHarnessConfig();
184 } catch (Exception e) {
185 log.error("Caught exception attempting to load test harness prior to aggregating suite lifecycles.");
186 }
187 return Integer.parseInt(cfgCtx.getProperty(KEWConstants.HTTP_SERVICE_PORT));
188 }
189
190 protected String getJettyServerContextName() {
191 Config cfgCtx = null;
192 try {
193 cfgCtx = getTestHarnessConfig();
194 } catch (Exception e) {
195 log.error("Caught exception attempting to load test harness prior to aggregating suite lifecycles.");
196 }
197 return cfgCtx.getProperty(KEWConstants.KEW_SERVER_CONTEXT);
198 }
199
200 protected String getJettyServerRelativeWebappRoot() {
201 return "/../web/src/main/webapp/kew";
202 }
203
204 /**
205 * Adds any ResourceLoaders that have been registered for WebAppClassLoaders
206 * to the GlobalResourceLoader
207 */
208 private class InitializeGRL extends BaseLifecycle {
209 @Override
210 public void start() throws Exception {
211 org.kuali.rice.test.TestUtilities.addWebappsToContext();
212 super.start();
213 }
214
215 }
216
217 /**
218 * Flushes the KEW cache(s)
219 */
220 public class ClearCacheLifecycle extends BaseLifecycle {
221 @Override
222 public void stop() throws Exception {
223 KEWServiceLocator.getCacheAdministrator().flushAll();
224 KIMServiceLocator.getIdentityManagementService().flushAllCaches();
225 KIMServiceLocator.getRoleManagementService().flushRoleCaches();
226 super.stop();
227 }
228
229 }
230
231 /**
232 * Returns the List of tables that should be cleared on every test run.
233 */
234 protected List<String> getPerTestTablesToClear() {
235 List<String> tablesToClear = new ArrayList<String>();
236 tablesToClear.add("KREW_.*");
237 tablesToClear.add("KRSB_.*");
238 tablesToClear.add("KREN_.*");
239 return tablesToClear;
240 }
241
242 protected List<String> getPerTestTablesNotToClear() {
243 return new ArrayList<String>();
244 }
245
246 /**
247 * By default this loads the "default" data set from the DefaultTestData.sql
248 * and DefaultTestData.xml files. Subclasses can override this to change
249 * this behaviour
250 */
251 protected void loadDefaultTestData() throws Exception {
252 // at this point this is constants. loading these through xml import is
253 // problematic because of cache notification
254 // issues in certain low level constants.
255 new SQLDataLoader(
256 "classpath:org/kuali/rice/kew/test/DefaultPerTestData.sql", ";")
257 .runSql();
258
259 KEWXmlDataLoader.loadXmlClassLoaderResource(KEWTestCase.class,
260 "DefaultPerTestData.xml");
261 GlobalVariables.setMessageMap(new MessageMap());
262 }
263
264 protected void loadXmlFile(String fileName) {
265 try {
266 KEWXmlDataLoader.loadXmlClassLoaderResource(getClass(), fileName);
267 } catch (Exception e) {
268 throw new WorkflowRuntimeException(e);
269 }
270 }
271
272 protected void loadXmlFile(Class clazz, String fileName) {
273 try {
274 KEWXmlDataLoader.loadXmlClassLoaderResource(clazz, fileName);
275 } catch (Exception e) {
276 throw new WorkflowRuntimeException(e);
277 }
278 }
279
280 protected void loadXmlFileFromFileSystem(String fileName) {
281 try {
282 KEWXmlDataLoader.loadXmlFile(fileName);
283 } catch (Exception e) {
284 throw new WorkflowRuntimeException(e);
285 }
286 }
287
288 protected void loadXmlStream(InputStream xmlStream) {
289 try {
290 KEWXmlDataLoader.loadXmlStream(xmlStream);
291 } catch (Exception e) {
292 throw new WorkflowRuntimeException(e);
293 }
294 }
295
296 protected String getPrincipalIdForName(String principalName) {
297 return KEWServiceLocator.getIdentityHelperService()
298 .getIdForPrincipalName(principalName);
299 }
300
301 protected String getPrincipalNameForId(String principalId) {
302 return KEWServiceLocator.getIdentityHelperService().getPrincipal(
303 principalId).getPrincipalName();
304 }
305
306 protected String getGroupIdForName(String namespace, String groupName) {
307 return KEWServiceLocator.getIdentityHelperService().getIdForGroupName(
308 namespace, groupName);
309 }
310 }